4

Situation:

When I'm trying to mux jpegs to mkv file I'll get a zero sized file. I must put encode and decode elements between parser and muxer for correct output. When I'm muxing a h264 video with same code I'll get correct video file, that means the time setting of buffers should be OK(duration and pts parameter). Anyway after bad buffer settings is size of file not zero. Matroskamux requires on sink pad for "image/jpeg" only "width" and "heigth" capabilities but it looks like that this is not sufficient. Jpegparse is giving correct values and the program does not work after manual setting of this capabilities too.

Example of pipeline:

This pipeline doesn't work

appsrc ! "image/jpeg" ! jpegparse ! matroskamux ! filesink location=mjpeg.mkv

But this works

appsrc ! "image/jpeg" ! jpegparse ! avdec_mjpeg ! x264enc ! matroskamux ! filesink location=mjpeg.mkv

Example of code:

Working code, but with reencoding

    app = new _App();

    app->src = (GstAppSrc*)gst_element_factory_make ("appsrc", "source");

    if(IsH264Frame(codecType))
        app->parser = gst_element_factory_make("h264parse", "parser");
    else if(codecType == IMAGE_MJPEG_FRAME)
        app->parser = gst_element_factory_make("jpegparse", "parser");

        //additional code
    app->decoder = gst_element_factory_make("avdec_mjpeg", "decoder");
    app->encoder = gst_element_factory_make("x264enc", "encoder");

    app->muxer = gst_element_factory_make("matroskamux", "muxer");
    app->sink = (GstAppSink*)gst_element_factory_make ("filesink", "sink");


    if (!app->pipeline || !app->src || !app->decoder || !app->encoder || !app->muxer || !app->sink || !app->parser)
        return;



    app->bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline));
    g_assert(app->bus);
    gst_bus_add_watch (app->bus, (GstBusFunc) BusMessage, this);


    gst_bin_add_many (GST_BIN (app->pipeline), (GstElement*)app->src, app->decoder, app->encoder, app->muxer, app->sink, app->parser
        ,NULL);


            /*          SETUP ELEMENTS          */


    g_object_set(app->src,
        "stream-type", 0,
        "format", GST_FORMAT_BUFFERS, 
        "is-live", true,
        "block", true,
        NULL);

    if(IsH264Frame(codecType)){

        g_object_set(app->src, "caps", gst_caps_new_simple("video/x-h264",
            NULL), NULL);

    } else if(codecType == IMAGE_MJPEG_FRAME) {

        g_object_set(app->src, "caps", gst_caps_new_simple("image/jpeg",
            "framerate",GST_TYPE_FRACTION,(int)framerate,1, 
            NULL), NULL);

        //additional code

        g_object_set(app->decoder, "caps", gst_caps_new_simple("video/x-raw",
            NULL), NULL);

        g_object_set(app->encoder, "caps", gst_caps_new_simple("video/x-h264",
            NULL), NULL);

    }


    g_signal_connect(app->src, "need-data", G_CALLBACK(StartFeed), this);
    g_signal_connect(app->src, "enough-data", G_CALLBACK(StopFeed), this);


    g_object_set (app->sink, 
        "location", GenerateFileName().c_str(),
        "buffer-mode", 0,
        NULL);


      /*            LINKING         */


    GstPad *padDecSrc, *padMuxSink, *parserSrc,
    GstPadTemplate *mux_sink_pad_template;

    mux_sink_pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (app->muxer), "video_%u");
    padMuxSink = gst_element_request_pad (app->muxer, mux_sink_pad_template, NULL, NULL);

    parserSrc = gst_element_get_static_pad (app->parser, "src");
    padEncSrc = gst_element_get_static_pad (app->encoder, "src");


    if(!gst_element_link( (GstElement*)app->src,  app->parser))
            return;

    if(IsH264Frame(codecType)){

        if(gst_pad_link (parserSrc, padMuxSink) != GST_PAD_LINK_OK)
            return;

    } else if(codecType == IMAGE_MJPEG_FRAME){ 

        //additional code
        if(!gst_element_link( app->parser,  app->decoder))
            return;

        if(!gst_element_link( app->decoder,  app->encoder))
            return;

        if(gst_pad_link (padDecSrc, padMuxSink) != GST_PAD_LINK_OK)
            return;

    }

    if(!gst_element_link( app->muxer,  (GstElement*)app->sink))
        return;


            /*          PLAY            */


    GstStateChangeReturn ret = gst_element_set_state (app->pipeline, GST_STATE_PLAYING);

    if (ret == GST_STATE_CHANGE_FAILURE) 
    {
        gst_object_unref (app->pipeline);
        return;
    }

Question:

What I am doing wrong? Any ideas to solve this problem?

slayer69
  • 81
  • 9
  • Did you find a solution ? It is possible to create MJPEG files in a matroska container ? – rodrigob Apr 09 '14 at 13:25
  • Only this dirty re-encoding "solution". I'm planing to debug matroskamux element to check what's wrong but i haven't time for that now. Maybe a good idea is analyse jpeg image before and after re-encoding and check for differences. If you find solution please let me know here. – slayer69 Apr 12 '14 at 17:12
  • You haven't posted enough code to reproduce your issue - you need to provide code which actually pushes buffers through `appsrc` into the pipeline. The chances are that you are getting `Invalid buffer timestamp; dropping buffer` error from matroskamux due to unset timestamps in the buffers. – Michał Wróbel Apr 26 '14 at 14:05

1 Answers1

0

I solved this problem with change of appsrc property "format" from GST_FORMAT_BUFFERS to GST_FORMAT_TIME. Correct timestamps on buffers is not enought.

slayer69
  • 81
  • 9