[
http://opencast.jira.com/browse/MH-3708?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=30365#comment-30365
]
Greg Logan commented on MH-3708:
--------------------------------
Per
http://opencast.3480289.n2.nabble.com/JIRA-Ticket-Cleanup-proposal-td7475080.html,
this has been bulk resolved as won't fix. If this is still important to you
please reopen and we can triage as appropriate.
> It would be nice to be able to seek in lectures without a streaming server or
> using progressive download
> --------------------------------------------------------------------------------------------------------
>
> Key: MH-3708
> URL: http://opencast.jira.com/browse/MH-3708
> Project: Matterhorn Project
> Issue Type: Community Feature Request
> Components: Architecture & Services, Engage Tools
> Affects Versions: None
> Reporter: Christopher Brooks
> Priority: Minor
> Fix For: None
>
>
> This can be done using flvtool to inject metadata into the flv giving byte
> offset headers. This would need to be added to the workflow after the flv
> creation. Here is some java code (servlet) that then allows for the
> navigation using a get parameter indicating the byte offset the client is
> requesting:
> package ca.recollect.player;
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.IOException;
> import java.io.OutputStream;
> import java.sql.Connection;
> import java.sql.DriverManager;
> import java.sql.PreparedStatement;
> import java.sql.SQLException;
> import java.util.concurrent.ConcurrentLinkedQueue;
> import javax.persistence.EntityManager;
> import javax.persistence.EntityManagerFactory;
> import javax.persistence.Persistence;
> import javax.persistence.PersistenceUnit;
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServlet;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
> import org.apache.log4j.Logger;
> import ca.recollect.entities.Episode;
> import ca.recollect.shared.util.PropertyLoader;
> /**
> * This is a quick port of the code described at
> http://flashforever.blogspot.com/2005/11/flv-seeking-for-progressive-download.html
> * Use it however you feel like it. Also, check here for full specs:
> http://osflash.org/flv
> */
> public class Streamer extends HttpServlet {
> private static final long serialVersionUID = 1L;
> private static final Logger _logger = Logger.getLogger(Streamer.class);
> public static ConcurrentLinkedQueue<String[]> loggingData = null;
> //private static DBLogger datalogger = null;
> protected static final byte[] header = new byte[]{0x46, 0x4c, 0x56,
> 0x01, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
> private byte[] data = new byte[10240];
> private String _fileRoot = "";
> private static final String PERSISTENCE_UNIT = "StreamerPU";
> @PersistenceUnit(unitName = PERSISTENCE_UNIT)
> private EntityManagerFactory emf = null;
> @Override
> public void init() throws ServletException {
> PropertyLoader loader = new
> PropertyLoader("/META-INF/streamer.properties");
> _fileRoot = loader.getStringProperty("video.fileroot");
> super.init();
> emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
> _logger.info("Streamer started successfully");
> }
> /** Processes requests for both HTTP <code>GET</code> and
> <code>POST</code> methods.
> * @param request servlet request
> * @param response servlet response
> * @throws IOException
> */
> protected void processRequest(HttpServletRequest request,
> HttpServletResponse response) throws IOException {
> if (_logger.isDebugEnabled()) {
> _logger.debug("processRequest()");
> }
> boolean throttled = true;
> String throttling = request.getParameter("throttled");
> if (throttling != null && throttling.equals("false")) {
> throttled = false;
> }
> FileInputStream fileStream = null;
> long file = 0;
> OutputStream out = null;
> long position = 0;
> long filelength = 0;
> int eof = 0;
> try {
> response.setContentType("video/x-flv");
> //get the file parameter from the request
> try {
> file =
> Long.parseLong(request.getParameter("file"));
> } catch (NumberFormatException ex) {
> _logger.error("No episode specified!");
> response.setContentLength(0);
> return;
> }
> _logger.debug("processRequest(): Getting video id=" +
> file);
> //Create the entity manager
> EntityManager em = emf.createEntityManager();
> Episode ep = em.find(Episode.class, file);
> if (ep == null) {
> _logger.info("No result found");
> return;
> }
> //Check to make sure the file exists
> File inputFile = new File(_fileRoot, ep.getFilename());
> if (!inputFile.isFile()) {
> _logger.info("Episode: " +
> inputFile.getAbsolutePath() + " not found in filesystem");
> response.setContentLength(0);
> return;
> }
> //Start sending stuff to the client
> fileStream = new FileInputStream(inputFile);
> //seek to the position indicated by the stream
> position = 0;
> //seek to the position indicated by the stream
> try {
> position +=
> Long.parseLong(request.getParameter("position"));
> } catch (NumberFormatException e) {
> //we'll just assume they want to start at the
> begining, so do nothing
> }
> fileStream.skip(position);
> //set the http header for content length
> //this is needed for flash player 9, so it knows max on
> the timeline
> filelength = inputFile.length();
> if (position > 0) {
> response.setContentLength((int) (filelength -
> position + 1));
> } else {
> response.setContentLength((int) (filelength));
> }
> //get the output stream to respond with
> out = response.getOutputStream();
> //write out the header
> eof = data.length;
> if (position != 0) {
> out.write(header);
> }
> //cur = position;
> //write out the data
> while (eof == data.length) {
> eof = fileStream.read(data);
> long start = System.currentTimeMillis();
> out.write(data, 0, eof);
> out.flush();
> long end = System.currentTimeMillis();
> if (throttled && end - start < 25) {
> try {
> Thread.sleep(25);
> } catch (InterruptedException e) {}
> }
> }
> //close connection
> out.close();
> out = null;
> } catch (IOException ex) {
> _logger.error(ex);
> } finally {
> //close the file stream
> if (fileStream != null) {
> fileStream.close();
> }
> fileStream = null;
> //close the response stream in case
> if (out != null) {
> out.close();
> }
> }
> }
> // <editor-fold defaultstate="collapsed" desc="HttpServlet methods.
> Click on the + sign on the left to edit the code.">
> /** Handles the HTTP <code>GET</code> method.
> * @param request servlet request
> * @param response servlet response
> * @throws ServletException
> * @throws IOException
> */
> @Override
> protected void doGet(HttpServletRequest request, HttpServletResponse
> response)
> throws ServletException, IOException {
> processRequest(request, response);
> }
> /** Handles the HTTP <code>POST</code> method.
> * @param request servlet request
> * @param response servlet response
> * @throws ServletException
> * @throws IOException
> */
> @Override
> protected void doPost(HttpServletRequest request, HttpServletResponse
> response)
> throws ServletException, IOException {
> processRequest(request, response);
> }
> /** Returns a short description of the servlet.
> * @return A description of the servlet
> */
> @Override
> public String getServletInfo() {
> return "Streams video files";
> }
> // </editor-fold>
> }
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators:
http://opencast.jira.com/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira
_______________________________________________
Matterhorn mailing list
[email protected]
http://lists.opencastproject.org/mailman/listinfo/matterhorn
To unsubscribe please email
[email protected]
_______________________________________________