2012-01-05 112 views
2

私は、私が書いたトランスポートストリームデマルチプレクサからAVを再生するためのgstreamer appsrcプラグインを学習しようとしています(プラグインはすでに利用可能であると知っています。私は、MPEGトランスポートストリームからオーディオおよびビデオのエレメンタリーストリームを抽出しました。今私はappsrcプラグインにプッシュし、gstパイプラインを使って再生する必要があります(この部分はまだ私には分かりません:どのプラグインを使うべきか - どのようなヒントも高く評価されます)。gstreamer appsrcテストアプリケーション

私はsample code on using appsrcを見つけましたが、それを実行すると出力はありません。私はstart_feedread_data関数が実際に呼び出されたことを確認しました。 read_data機能では、データをプッシュするか否かを決定するためにタイマーチェックがあります:

ms = g_timer_elapsed(app->timer, NULL); 
printf("ms %f\n", ms); 
if (ms > 1.0/20.0) { 

私はこのタイマーが何のためにあるのかわからないが、msの値は常に周り0.035であり、データがプッシュされることはありませんappsrcに入れます。だから私はif(ms > 0.03)にあれば条件を変更したが、その後、私は内部データフローのエラーを得た:

ms 0.033747 
ms 0.000010 
ERROR from element mysource: Internal data flow error. 
Debugging info: gstbasesrc.c(2582): gst_base_src_loop(): /GstPipeline:pipeline0/GstAppSrc:mysource: 
streaming task paused, reason not-negotiated (-4) 

誰かがどのようにビデオを見るために、これを微調整する方法を教えすることはできますか?リンクされたウェブサイトのコードを以下に示します。

#include <gst/gst.h> 
#include <gst/app/gstappsrc.h> 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

#include <gdk-pixbuf/gdk-pixbuf.h> 

GST_DEBUG_CATEGORY (appsrc_pipeline_debug); 
#define GST_CAT_DEFAULT appsrc_pipeline_debug 

typedef struct _App App; 

struct _App 
{ 
    GstElement *pipeline; 
    GstElement *appsrc; 

    GMainLoop *loop; 
    guint sourceid; 

    GTimer *timer; 

}; 

App s_app; 

static gboolean 
read_data (App * app) 
{ 
    guint len; 
    GstFlowReturn ret; 
    gdouble ms; 

    ms = g_timer_elapsed(app->timer, NULL); 
    printf("ms %f\n", ms); 
    if (ms > 1.0/20.0) { 
     GstBuffer *buffer; 
     GdkPixbuf *pb; 
     gboolean ok = TRUE; 

     buffer = gst_buffer_new(); 

     pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 640, 480); 
     gdk_pixbuf_fill(pb, 0xffffffff); 

     GST_BUFFER_DATA (buffer) = gdk_pixbuf_get_pixels(pb); 
     GST_BUFFER_SIZE (buffer) = 640*480*3*sizeof(guchar); 

     GST_DEBUG ("feed buffer"); 
     g_signal_emit_by_name (app->appsrc, "push-buffer", buffer, &ret); 
     gst_buffer_unref (buffer); 

     if (ret != GST_FLOW_OK) { 
      /* some error, stop sending data */ 
      GST_DEBUG ("some error"); 
      ok = FALSE; 
     } 

     g_timer_start(app->timer); 

     return ok; 
    } 

    // g_signal_emit_by_name (app->appsrc, "end-of-stream", &ret); 
    return FALSE; 
} 

/* This signal callback is called when appsrc needs data, we add an idle handler 
* to the mainloop to start pushing data into the appsrc */ 
static void 
start_feed (GstElement * pipeline, guint size, App * app) 
{ 
    if (app->sourceid == 0) { 
    GST_DEBUG ("start feeding"); 
    app->sourceid = g_idle_add ((GSourceFunc) read_data, app); 
    } 
} 

/* This callback is called when appsrc has enough data and we can stop sending. 
* We remove the idle handler from the mainloop */ 
static void 
stop_feed (GstElement * pipeline, App * app) 
{ 
    if (app->sourceid != 0) { 
    GST_DEBUG ("stop feeding"); 
    g_source_remove (app->sourceid); 
    app->sourceid = 0; 
    } 
} 

static gboolean 
bus_message (GstBus * bus, GstMessage * message, App * app) 
{ 
    GST_DEBUG ("got message %s", 
     gst_message_type_get_name (GST_MESSAGE_TYPE (message))); 

    switch (GST_MESSAGE_TYPE (message)) { 
    case GST_MESSAGE_ERROR: { 
     GError *err = NULL; 
     gchar *dbg_info = NULL; 

     gst_message_parse_error (message, &err, &dbg_info); 
     g_printerr ("ERROR from element %s: %s\n", 
      GST_OBJECT_NAME (message->src), err->message); 
     g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); 
     g_error_free (err); 
     g_free (dbg_info); 
     g_main_loop_quit (app->loop); 
     break; 
    } 
    case GST_MESSAGE_EOS: 
     g_main_loop_quit (app->loop); 
     break; 
    default: 
     break; 
    } 
    return TRUE; 
} 

int 
main (int argc, char *argv[]) 
{ 
    App *app = &s_app; 
    GError *error = NULL; 
    GstBus *bus; 
    GstCaps *caps; 

    gst_init (&argc, &argv); 

    GST_DEBUG_CATEGORY_INIT (appsrc_pipeline_debug, "appsrc-pipeline", 0, 
     "appsrc pipeline example"); 

    /* create a mainloop to get messages and to handle the idle handler that will 
* feed data to appsrc. */ 
    app->loop = g_main_loop_new (NULL, TRUE); 
    app->timer = g_timer_new(); 

    app->pipeline = gst_parse_launch("appsrc name=mysource ! video/x-raw-rgb,width=640,height=480,bpp=24,depth=24 ! ffmpegcolorspace ! videoscale method=1 ! theoraenc bitrate=150 ! udpsink host=127.0.0.1 port=1234", NULL); 
    g_assert (app->pipeline); 

    bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline)); 
    g_assert(bus); 

    /* add watch for messages */ 
    gst_bus_add_watch (bus, (GstBusFunc) bus_message, app); 

    /* get the appsrc */ 
    app->appsrc = gst_bin_get_by_name (GST_BIN(app->pipeline), "mysource"); 
    g_assert(app->appsrc); 
    g_assert(GST_IS_APP_SRC(app->appsrc)); 
    g_signal_connect (app->appsrc, "need-data", G_CALLBACK (start_feed), app); 
    g_signal_connect (app->appsrc, "enough-data", G_CALLBACK (stop_feed), app); 

    /* set the caps on the source */ 
    caps = gst_caps_new_simple ("video/x-raw-rgb", 
    "bpp",G_TYPE_INT,24, 
    "depth",G_TYPE_INT,24, 
    "width", G_TYPE_INT, 640, 
    "height", G_TYPE_INT, 480, 
    NULL); 
    gst_app_src_set_caps(GST_APP_SRC(app->appsrc), caps); 


    /* go to playing and wait in a mainloop. */ 
    gst_element_set_state (app->pipeline, GST_STATE_PLAYING); 

    /* this mainloop is stopped when we receive an error or EOS */ 
    g_main_loop_run (app->loop); 

    GST_DEBUG ("stopping"); 

    gst_element_set_state (app->pipeline, GST_STATE_NULL); 

    gst_object_unref (bus); 
    g_main_loop_unref (app->loop); 

    return 0; 
} 

アップデート:私は、通常のxvimagesinkでudpsink交換しようと、誰も答えることを気にしていないので、それは

+0

私が投稿した回答はappsrcテストコードの作業バージョンですが、なぜこの特定のコードが機能しないのかという質問には本当に答えません。あなたが答えを知っているなら、投稿してください。 – Amarghosh

答えて

9

を助けていない、私はappsrcプラグインの作業のテストコードを掲載します - これはしませんが質問のコードがうまくいかない理由に答えると、appsrcテストコードを検索したときにGoogleからここに来るのに役立ちます。 IRC/freenodeの/#のgstreamerの上の達人に非常に感謝して

#include <stdio.h> 
#include <gst/gst.h> 
#include <gst/app/gstappsrc.h> 

typedef struct { 
    GstPipeline *pipeline; 
    GstAppSrc *src; 
    GstElement *sink; 
    GstElement *decoder; 
    GstElement *ffmpeg; 
    GstElement *xvimagesink; 
    GMainLoop *loop; 
    guint sourceid; 
    FILE *file; 
}gst_app_t; 

static gst_app_t gst_app; 

#define BUFF_SIZE (1024) 

static gboolean read_data(gst_app_t *app) 
{ 
    GstBuffer *buffer; 
    guint8 *ptr; 
    gint size; 
    GstFlowReturn ret; 

    ptr = g_malloc(BUFF_SIZE); 
    g_assert(ptr); 

    size = fread(ptr, 1, BUFF_SIZE, app->file); 

    if(size == 0){ 
     ret = gst_app_src_end_of_stream(app->src); 
     g_debug("eos returned %d at %d\n", ret, __LINE__); 
     return FALSE; 
    } 

    buffer = gst_buffer_new(); 
    GST_BUFFER_MALLOCDATA(buffer) = ptr; 
    GST_BUFFER_SIZE(buffer) = size; 
    GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); 

    ret = gst_app_src_push_buffer(app->src, buffer); 

    if(ret != GST_FLOW_OK){ 
     g_debug("push buffer returned %d for %d bytes \n", ret, size); 
     return FALSE; 
    } 

    if(size != BUFF_SIZE){ 
     ret = gst_app_src_end_of_stream(app->src); 
     g_debug("eos returned %d at %d\n", ret, __LINE__); 
     return FALSE; 
    } 

    return TRUE; 
} 

static void start_feed (GstElement * pipeline, guint size, gst_app_t *app) 
{ 
    if (app->sourceid == 0) { 
     GST_DEBUG ("start feeding"); 
     app->sourceid = g_idle_add ((GSourceFunc) read_data, app); 
    } 
} 

static void stop_feed (GstElement * pipeline, gst_app_t *app) 
{ 
    if (app->sourceid != 0) { 
     GST_DEBUG ("stop feeding"); 
     g_source_remove (app->sourceid); 
     app->sourceid = 0; 
    } 
} 

static void on_pad_added(GstElement *element, GstPad *pad) 
{ 
    GstCaps *caps; 
    GstStructure *str; 
    gchar *name; 
    GstPad *ffmpegsink; 
    GstPadLinkReturn ret; 

    g_debug("pad added"); 

    caps = gst_pad_get_caps(pad); 
    str = gst_caps_get_structure(caps, 0); 

    g_assert(str); 

    name = (gchar*)gst_structure_get_name(str); 

    g_debug("pad name %s", name); 

    if(g_strrstr(name, "video")){ 

     ffmpegsink = gst_element_get_pad(gst_app.ffmpeg, "sink"); 
     g_assert(ffmpegsink); 
     ret = gst_pad_link(pad, ffmpegsink); 
     g_debug("pad_link returned %d\n", ret); 
     gst_object_unref(ffmpegsink); 
    } 
    gst_caps_unref(caps); 
} 

static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer *ptr) 
{ 
    gst_app_t *app = (gst_app_t*)ptr; 

    switch(GST_MESSAGE_TYPE(message)){ 

    case GST_MESSAGE_ERROR:{ 
     gchar *debug; 
     GError *err; 

     gst_message_parse_error(message, &err, &debug); 
     g_print("Error %s\n", err->message); 
     g_error_free(err); 
     g_free(debug); 
     g_main_loop_quit(app->loop); 
    } 
    break; 

    case GST_MESSAGE_EOS: 
     g_print("End of stream\n"); 
     g_main_loop_quit(app->loop); 
     break; 

    default: 
     g_print("got message %s\n", \ 
      gst_message_type_get_name (GST_MESSAGE_TYPE (message))); 
     break; 
    } 

    return TRUE; 
} 

int main(int argc, char *argv[]) 
{ 
    gst_app_t *app = &gst_app; 
    GstBus *bus; 
    GstStateChangeReturn state_ret; 

    if(argc != 2){ 
     printf("File name not specified\n"); 
     return 1; 
    } 

    app->file = fopen(argv[1], "r"); 

    g_assert(app->file); 

    gst_init(NULL, NULL); 

    app->pipeline = (GstPipeline*)gst_pipeline_new("mypipeline"); 
    bus = gst_pipeline_get_bus(app->pipeline); 
    gst_bus_add_watch(bus, (GstBusFunc)bus_callback, app); 
    gst_object_unref(bus); 

    app->src = (GstAppSrc*)gst_element_factory_make("appsrc", "mysrc"); 
    app->decoder = gst_element_factory_make("decodebin", "mydecoder"); 
    app->ffmpeg = gst_element_factory_make("ffmpegcolorspace", "myffmpeg"); 
    app->xvimagesink = gst_element_factory_make("xvimagesink", "myvsink"); 

    g_assert(app->src); 
    g_assert(app->decoder); 
    g_assert(app->ffmpeg); 
    g_assert(app->xvimagesink); 

    g_signal_connect(app->src, "need-data", G_CALLBACK(start_feed), app); 
    g_signal_connect(app->src, "enough-data", G_CALLBACK(stop_feed), app); 
    g_signal_connect(app->decoder, "pad-added", G_CALLBACK(on_pad_added), app->decoder); 

    gst_bin_add_many(GST_BIN(app->pipeline), (GstElement*)app->src, app->decoder, app->ffmpeg, app->xvimagesink, NULL); 

    if(!gst_element_link((GstElement*)app->src, app->decoder)){ 
     g_warning("failed to link src anbd decoder"); 
    } 

    if(!gst_element_link(app->ffmpeg, app->xvimagesink)){ 
     g_warning("failed to link ffmpeg and xvsink"); 
    } 

    state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_PLAYING); 
    g_warning("set state returned %d\n", state_ret); 

    app->loop = g_main_loop_new(NULL, FALSE); 
    printf("Running main loop\n"); 
    g_main_loop_run(app->loop); 

    state_ret = gst_element_set_state((GstElement*)app->pipeline, GST_STATE_NULL); 
    g_warning("set state null returned %d\n", state_ret); 

    return 0; 
} 
2

(特に__tim!)、私はあなたのサンプルコードのバグを修正する方法を考え出しました。

バグ1.この関数がバスに残り、繰り返し呼び出されるように、read_data()の最後の行は "TRUE"を返します。データの送信を完全に停止したい場合にのみ、FALSEを返します。

バグ2. gst_caps_new_simple()をgst_video_format_new_caps()に置き換えます。また、gst/video/video.hを、-lgstvideo-0.10にリンクする必要があります。

ここに私のバージョンのコードがあります。イメージの表示方法と、UDPを使ってtheora-encodedバージョンをストリームする方法の両方を示しています。 theoraが一定のフレームレートソースを期待しているので、後者の場合のビデオの使用方法に注意してください。

#include <gst/gst.h> 
#include <gst/app/gstappsrc.h> 
#include <gst/video/video.h> 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

#include <gdk-pixbuf/gdk-pixbuf.h> 

GST_DEBUG_CATEGORY (appsrc_pipeline_debug); 
#define GST_CAT_DEFAULT appsrc_pipeline_debug 

typedef struct _App App; 

struct _App 
{ 
    GstElement *pipeline; 
    GstElement *appsrc; 

    GMainLoop *loop; 
    guint sourceid; 

    GTimer *timer; 

}; 

App s_app; 

static gboolean 
read_data (App * app) 
{ 
    guint len; 
    GstFlowReturn ret; 
    gdouble ms; 

    ms = g_timer_elapsed(app->timer, NULL); 
    if (ms > 1.0/20.0) { 
     GstBuffer *buffer; 
     GdkPixbuf *pb; 
     gboolean ok = TRUE; 

     buffer = gst_buffer_new(); 

     pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 640, 480); 
     gdk_pixbuf_fill(pb, 0xffffffff); 

     GST_BUFFER_DATA (buffer) = gdk_pixbuf_get_pixels(pb); 
     GST_BUFFER_SIZE (buffer) = 640*480*3*sizeof(guchar); 

     GST_DEBUG ("feed buffer"); 
     g_signal_emit_by_name (app->appsrc, "push-buffer", buffer, &ret); 
     gst_buffer_unref (buffer); 

     if (ret != GST_FLOW_OK) { 
      /* some error, stop sending data */ 
      GST_DEBUG ("some error"); 
      ok = FALSE; 
     } 

     g_timer_start(app->timer); 

     return ok; 
    } 

    // g_signal_emit_by_name (app->appsrc, "end-of-stream", &ret); 
    return TRUE; 
} 

/* This signal callback is called when appsrc needs data, we add an idle handler 
* to the mainloop to start pushing data into the appsrc */ 
static void 
start_feed (GstElement * pipeline, guint size, App * app) 
{ 
    if (app->sourceid == 0) { 
    GST_DEBUG ("start feeding"); 
    app->sourceid = g_idle_add ((GSourceFunc) read_data, app); 
    } 
} 

/* This callback is called when appsrc has enough data and we can stop sending. 
* We remove the idle handler from the mainloop */ 
static void 
stop_feed (GstElement * pipeline, App * app) 
{ 
    if (app->sourceid != 0) { 
    GST_DEBUG ("stop feeding"); 
    g_source_remove (app->sourceid); 
    app->sourceid = 0; 
    } 
} 

static gboolean 
bus_message (GstBus * bus, GstMessage * message, App * app) 
{ 
    GST_DEBUG ("got message %s", 
     gst_message_type_get_name (GST_MESSAGE_TYPE (message))); 

    switch (GST_MESSAGE_TYPE (message)) { 
    case GST_MESSAGE_ERROR: { 
     GError *err = NULL; 
     gchar *dbg_info = NULL; 

     gst_message_parse_error (message, &err, &dbg_info); 
     g_printerr ("ERROR from element %s: %s\n", 
      GST_OBJECT_NAME (message->src), err->message); 
     g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none"); 
     g_error_free (err); 
     g_free (dbg_info); 
     g_main_loop_quit (app->loop); 
     break; 
    } 
    case GST_MESSAGE_EOS: 
     g_main_loop_quit (app->loop); 
     break; 
    default: 
     break; 
    } 
    return TRUE; 
} 

int 
main (int argc, char *argv[]) 
{ 
    App *app = &s_app; 
    GError *error = NULL; 
    GstBus *bus; 
    GstCaps *caps; 

    gst_init (&argc, &argv); 

    GST_DEBUG_CATEGORY_INIT (appsrc_pipeline_debug, "appsrc-pipeline", 0, 
     "appsrc pipeline example"); 

    /* create a mainloop to get messages and to handle the idle handler that will 
* feed data to appsrc. */ 
    app->loop = g_main_loop_new (NULL, TRUE); 
    app->timer = g_timer_new(); 

    // Option 1: Display on screen via xvimagesink 
    app->pipeline = gst_parse_launch("appsrc name=mysource ! video/x-raw-rgb,width=640,height=480 ! ffmpegcolorspace ! videoscale method=1 ! xvimagesink", NULL); 

    // Option 2: Encode using Theora and stream through UDP 
    // NOTE: first launch receiver by executing: 
    //  gst-launch udpsrc port=5000 ! theoradec ! ffmpegcolorspace ! xvimagesink 
    //app->pipeline = gst_parse_launch("appsrc name=mysource ! videorate ! ffmpegcolorspace ! videoscale method=1 ! video/x-raw-yuv,width=640,height=480,framerate=\(fraction\)15/1 ! theoraenc bitrate=700 ! udpsink host=127.0.0.1 port=5000", NULL); 

    g_assert (app->pipeline); 

    bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline)); 
    g_assert(bus); 

    /* add watch for messages */ 
    gst_bus_add_watch (bus, (GstBusFunc) bus_message, app); 

    /* get the appsrc */ 
    app->appsrc = gst_bin_get_by_name (GST_BIN(app->pipeline), "mysource"); 
    g_assert(app->appsrc); 
    g_assert(GST_IS_APP_SRC(app->appsrc)); 
    g_signal_connect (app->appsrc, "need-data", G_CALLBACK (start_feed), app); 
    g_signal_connect (app->appsrc, "enough-data", G_CALLBACK (stop_feed), app); 

    /* set the caps on the source */ 
    caps = gst_video_format_new_caps(GST_VIDEO_FORMAT_RGB, 640, 480, 0, 1, 4, 3); 
    gst_app_src_set_caps(GST_APP_SRC(app->appsrc), caps); 


    /* go to playing and wait in a mainloop. */ 
    gst_element_set_state (app->pipeline, GST_STATE_PLAYING); 

    /* this mainloop is stopped when we receive an error or EOS */ 
    g_main_loop_run (app->loop); 

    GST_DEBUG ("stopping"); 

    gst_element_set_state (app->pipeline, GST_STATE_NULL); 

    gst_object_unref (bus); 
    g_main_loop_unref (app->loop); 

    return 0; 
} 
関連する問題