How to create a webm file optimized for streaming

537 views
Skip to first unread message

power...@gmail.com

unread,
Apr 15, 2016, 10:23:20 AM4/15/16
to WebM Discussion, Albert M Sheldon IV
I posted this on stack overflow but I also wanted to get the opinion of you guys over here.

I have a feature in my application that captures the screen in realtime and writes it out to a WebM file using the VP8 codec. I was never able to get the cues and seek elements quite right and was able to use the mkclean tool to get those elements setup correctly.

I am now recording to VP9. Most of my code works fine for VP9 and I'm getting a valid file (checked by mkvalidator) however it does not seek correctly. I attempted to use mkclean again to fix this however it does not accept VP9 encoded files. As such when I attempt to seek within the file VLC, Chrome and Firefox they fail to seek correctly.

I have been using the example code from libvpx in the file webmenc.cc to create the WebM file. It looks like it creates a seek element and then puts the cues element at the end. I added one line in the `write_webm_file_header` to ensure that the cues are added to the correct track segment->CuesTrack(video_track_id);. I added to the write_webm_file_footer function to move the cues element to the front of the file.

    void write_webm_file_footer(struct EbmlGlobal *glob, const std::string& filename, const std::string& tempFilename)
   
{
        mkvmuxer
::MkvWriter *const writer =
           
reinterpret_cast<mkvmuxer::MkvWriter*>(glob->writer);
        mkvmuxer
::Segment *const segment =
           
reinterpret_cast<mkvmuxer::Segment*>(glob->segment);
        segment
->Finalize();
        writer
->Close();
        fclose
(glob->stream);
   
        FILE
* recordedFile;
       
const errno_t e_orig = fopen_s(&recordedFile, filename.c_str(), "rb+");
       
if (e_orig)
       
{
            printf
("\n Filename is invalid or error while opening <%s>.\n", filename.c_str());
           
return;// EXIT_FAILURE;
       
}
        mkvparser
::MkvReader* reader = new mkvparser::MkvReader(recordedFile);
   
        FILE
* tempFilePointer;
       
const errno_t e_temp = fopen_s(&tempFilePointer, tempFilename.c_str(), "wb+");
       
if (e_temp)
       
{
            printf
("\n Filename is invalid or error while opening <%s>.\n", tempFilename.c_str());
           
return;// EXIT_FAILURE;
       
}
        mkvmuxer
::MkvWriter *tempWriter = new mkvmuxer::MkvWriter(tempFilePointer);
   
       
if (!segment->CopyAndMoveCuesBeforeClusters(reader, tempWriter)) {
            printf
("\n Unable to copy and move cues before clusters.\n");
           
return;// EXIT_FAILURE;
       
}
        reader
->Close();
        fclose
(recordedFile);
       
delete reader;
        tempWriter
->Close();
        fclose
(tempFilePointer);
       
delete tempWriter;
   
       
delete segment;
       
delete writer;
        glob
->writer = NULL;
        glob
->segment = NULL;
   
}


After this I have some code to remove the original file and then replace it with the temp file. I have tried calling `AddCuePoint` each time I put in a keyframe but that hasn't seemed to help. What am I missing?

I am working in Visual Studio 2013 on Windows 10 (although this application will be used on Windows 7 and up). I am using libvpx 1.5.0 (from the github tag) and libwebm 1.0.0.27 (also from the github tag).

Tom Finegan

unread,
Apr 15, 2016, 2:47:46 PM4/15/16
to WebM Discussion, Albert M Sheldon IV
I think it's possible that you're missing nothing and getting burned by default libvpx encode settings. Unless you're on a newish revision (i.e. close to current HEAD), the default encode settings can produce a file with only one keyframe. Check your keyframe distance settings, basically. 

One point: You don't need cues to seek. VLC and other players that can play WebM should be able to seek/find keyframes/resume playback on their own. They're just nice to have because it prevents the player from having to go looking for them.

Anyway, back on the default settings topic: If you have a VP9 stream with only one keyframe mkvmuxer is going to cut clusters whenever they reach max cluster duration. When this happens, a cue point is generated that points at the new cluster. When you only have one keyframe in your file, clusters that do not start with keyframes will be created, and a cue point will be created to point at this (technically) invalid cluster. If this is happening it explains your seeking problem-- basically, you can't seek in this type of file unless the player app your using is smart enough to decode every single frame between the time at which the seek started and the time where you landed.


I am working in Visual Studio 2013 on Windows 10 (although this application will be used on Windows 7 and up). I am using libvpx 1.5.0 (from the github tag) and libwebm 1.0.0.27 (also from the github tag).


I haven't really had a chance to dig more deeply into the above to figure out what's going on (beyond sharing the above suspicion), but have you looked at sample_muxer.cc (probably still sample_muxer.cpp in tag you're using)? From a look at the code above I believe that you have, but I just want to mention it.

Anyway, if you're certain you have more than one keyframe in the file, please reply here and I'll try to dig a bit more deeply into what's going on. Including an example output file from your encoder would help if this ends up being the case.
 

--
You received this message because you are subscribed to the Google Groups "WebM Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webm-discuss...@webmproject.org.
To post to this group, send email to webm-d...@webmproject.org.
Visit this group at https://groups.google.com/a/webmproject.org/group/webm-discuss/.
For more options, visit https://groups.google.com/a/webmproject.org/d/optout.

power...@gmail.com

unread,
Apr 18, 2016, 2:24:24 PM4/18/16
to WebM Discussion, amos.s...@calabrio.com
Thanks for responding Tom. I looked into my recordings and found that for a sample 5 minute recording (at 1 fps) I had 3 total key frames. Seemed a little low. I moved to a kf_max_dist of 25 (since clusters seem to be 30 seconds in my recordings). That seemed to fix every thing up. Thanks so much for your help!
Reply all
Reply to author
Forward
0 new messages