player --ffmpeg from a growing file

Developers
guhlda
2011-09-02
2013-04-25
  • guhlda

    guhlda - 2011-09-02

    Hello,

    I need to add to player the capability of playing a file (through -ffmpeg mostly) that is being written, for instance being captured at this moment. Now player plays the file size as it is when starting to play, it doesn't see the new data written to the file while playing.

    Where and how should I look ? In ffmpeg_source.c would it be sufficient to update the file length regularly ?

    Guhlda

     
  • guhlda

    guhlda - 2011-09-19

    Related to growing file, I have tested playing an IMX30_MXF_1A file while being captured. When reading with -mxf <filename>, I get the following error:

    > player --x11 --mxf aa.mxf
    Info: Version: version 0.91, build: Sep 18 2011 18:41:39
    Warning: Failed to open jog-shuttle device for exclusive access - will try again later
    ERROR: No partition with header metadata found, in mxf_op1a_reader.c:1122
    ERROR: 'op1a_initialise_reader(newReader, &headerPartition)' failed, in mxf_reader.c:563
    ERROR: 'init_mxf_reader_2(&mxfFile, newSource->dataModel, &newSource->mxfReader)' failed, in mxf_source.c:1117
    ERROR: Failed to open MXF file source
    Failed
    

    but reading with -ffmpeg <filename> I do not get this MXF header problem:

    > player --x11 --ffmpeg aa.mxf.mxf 
    Info: Version: version 0.91, build: Sep 18 2011 18:41:39
    Warning: Failed to open jog-shuttle device for exclusive access - will try again later
    Info: Failed to pass through connect stream 3 (sound, pcm)
    Info: Failed to pass through connect stream 4 (sound, pcm)
    Unlocked
    Playing
    Started
    Speed 1x
    Start of source reached: [S] 00:00:00:00
    

    For growing file support through player -ffmpeg, I have a first simple hack in fms_get_length(), return 0 as source-length when read mode is growing-file. Now I want to go beyond, being able to update source-length dynamically, resume when end-of-file is encoutered and new data comes in, etc…

    Can you give me some directions on player threads & objects model, where apparently there are source, sink and player threads ? What is what ? Is it possible to connect sources to sinks dynamically ? Etc…

    Thank you for your support !
    Guhlda

     
  • Philip de Nier

    Philip de Nier - 2011-09-21

    Sorry for the delay - I was a bit busy.

    The failure when using -mxf is caused by the file's header partition not specifying the header byte count and the player then assumes there is no header data. This happens because the MXF writing code has not taken into account the possibility that files are played before the recording has ended.

    You could add this line

    mMXFFile->updatePartitions();
    

    to the end of the D10MXFOP1AWriter::CreateFile() method in the libMXF++ D10MXFOP1AWriter code. That line will fill in the header (and index) byte counts in the header partition pack.

    You'll then see that the player's progress bar has a black interior which signals that the source has an unknown duration. The player will fail to read a frame when it reaches the end and will just pause. Press play and it should be able to continue if there is more essence.

    I'm not sure whether using the -ffmpeg option would be easier than -mxf. The ingex player's ffmpeg_source.c code is 'brittle' and not all formats support (frame accurate) seeking.

    One thing that might also be relevant is the mxfs_is_complete and mxfs_post_complete functions in mxf_source. These are used to support the preservation system's playback of files during copying off an LTO drive. These functions might provide a means to finalize the duration (by re-reading the header) when the file writing has completed.

    Note also that in addition to the MXF writing code not really supporting playback while recording, there is no guarantee that the writing of the header metadata is atomic. This means the player could fail if it tries to read it too early.

    Philip

     
  • guhlda

    guhlda - 2011-09-22

    Thank you, yes it is working.

    Now, problem is that player doesn't get the effective timecode but starts from 0:00:00:00. It shows the effective timecode if restarted once the file is finalized (capture terminated).

    What if I call mMXFFile->updatePartitions() after every write cycle ? Should it be done at the end of MXFOP1AWriter::WriteSamples(), after mContentPackage->Reset() ?

    Guhlda

     
  • Philip de Nier

    Philip de Nier - 2011-09-22

    In libMXF/examples/reader/mxf_reader.c, convert_position_to_timecode(), line ~327 you have this

        while (mxf_next_list_iter_element(&iter))
        {
            segment = (TimecodeSegment*)mxf_get_iter_element(&iter);
            if (segment->duration == -1) /* timecode segment with unknown duration */
            {
                frameCount = position - segmentStartPosition;
                foundTimecodeSegment = 1;
                break;
            }
            else if (position < segmentStartPosition + segment->duration)
            {
                frameCount = segment->startTimecode + (position - segmentStartPosition);
                foundTimecodeSegment = 1;
                break;
            }
            segmentStartPosition += segment->duration;
        }
    

    Change it to this:

        while (mxf_next_list_iter_element(&iter))
        {
            segment = (TimecodeSegment*)mxf_get_iter_element(&iter);
            if (segment->duration < 0 || position < segmentStartPosition + segment->duration)
            {
                frameCount = segment->startTimecode + (position - segmentStartPosition);
                foundTimecodeSegment = 1;
                break;
            }
            segmentStartPosition += segment->duration;
        }
    

    I'll probably make that change myself as well at some point and update the CVS unless I can remember why I did it like that 5 years ago.

    The control timecode is calculated from information extracted from the header metadata and this information is set  at the point that file writing starts. You therefore don't need to re-read or update anything to get the timecode information.

    Philip

     
  • guhlda

    guhlda - 2011-09-22

    Ohhk I thought it was still a problem in writer.

    And yes it works, many thanks.

    I'm working on growing file support through -ffmpeg. Once stable, I will provide you with patches for these features and others regarding timecode. Many features are implemented in a nexus_recorder.cpp, which is a cmd-line only Recorder, features that you might want to integrate in Recorder too.

    Guhlda

     
  • guhlda

    guhlda - 2011-09-29

    Philip,

    I'm still working on "growing file" support, with -ffmpeg <IMX30 MXF 1A> file and got a few progress, with the ability to start playing from latest written frames (player -start -1 tries to start reading from latest frame, -start -2 from previous one..). As ffmpeg seems unable to dynamically update a source state and size, I applied a method where the reader seeks to last known frames then reads the packets until EOF, thus incrementaly updating the source length. Then it rewinds a bit and starts reading at the desired position.

    Still it is very hard to get latency down, as with ffmpeg's MXF, as stated in the code, seek precision is not 1 frame but a second, so that up to 24 frames are to be read and discarded to reach the desired frame.

    A few questions:

    - Do you think this seek granularity is related to ffmpeg MXF implementation which would be storing seek indexes every 25 frames ?

    - Any way to seek faster (incrementaly) without reading the full packets ? Is it possible to seek incrementaly by 1 frame with ffmpeg ?

    - Do you think I can get better results if implementing such growing file feature in -mxf decoder ? Such as updating the file size regularly ? Is there a lot to modify on MXF writer and reader ?

    Note: my code should work with all files supported by -ffmpeg.

    Guhlda

     
  • Philip de Nier

    Philip de Nier - 2011-10-02

    Hi Guhlda,

    I'd forgotten about FFmpeg's limitations regarding seeking and I'm surprised the limitation is still there; have a look at mxf_read_seek at the end of mxfdec.c,
    http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/mxfdec.c;h=92d93f3b37c6206cad9fd9145298be857d03f78f;hb=HEAD. I seem to remember some talk on the FFmpeg mailing list about supporting index tables, but it appears that this hasn't been committed yet.

    As I pointed out before, the player's -ffmpeg source is far from optimal and so I'm sure improvements can be, such as avoiding decoding frames that will be discarded when the format is known to be intra-frame. I can see the advantage of the -ffmpeg source as it provides access to a much wider range of formats. However, most of the work in the player has been with the -mxf source

    Philip

     
  • guhlda

    guhlda - 2011-10-04

    Philip,

    With my growing-file feature, I can observe that the file is "played" out a bit slower that it is captured originally, without any sign of starvation from DVS sink.

    Can you detail me how is the source and sink handshake happening, through sdl_accept_frame ? If source is a bit too slow, missing frames should be warned on sink side, no ?

    Guhlda

     
  • Philip de Nier

    Philip de Nier - 2011-10-04

    Yes. The source calls sdl_accept_frame and this call gets passed to each source using the accept_frame callback until it reaches one of the stream connector (e.g. pass through connect for ffmpeg source). The stream connector then calls msk_accept_stream_frame which sends the data down the series of sinks.

    After the frame has been accepted, the same process happens for sdl_receive_frame etc.

    The DVS sink should be reporting dropped frames if frames are being dropped.

    Philip

     
  • guhlda

    guhlda - 2011-10-05

    Mmm I don't get the roles of these entities. How do they map to threads ?

    I'm testing playing out dvs_sdi shared mem with

    player --shm-in p
    

    . But apparently there are many many threads from source to sink, which might explain the difficulty of going lower than 6 FIFO buffers on DVS output. Right ?

    Provided I do not need mutiple sources and sinks, I might use another process than player. Do you have (test) code that is capable of playing out on SDI from dvs_sdi shared mem or that I could easily adapt ? What about code in common/dvs_hardware ?

    Guhlda

     
  • Philip de Nier

    Philip de Nier - 2011-10-05

    I don't see the connection between thread usage and a lower limit on the number of DVS FIFO buffers.
    Some sources, connectors and sinks use threads to decouple their inputs from their outputs. This improves performance and lowers variability that can would otherwise cause dropped frames.

    I think the player is the only piece of code that reads from the shared memory and plays out through SDI. You would have to add something like the shm_source.c code to the code in common/dvs_hardware.

    Philip

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks