2017-02-13 121 views
1

我想写音频缓冲到文件。的GStreamer appsrc到文件的例子

问题是该文件总是空的或应用程序立即停止Internal data flow error

实例是:

https://gist.github.com/nzjrs/725122/16ceee88aafae389bab207818e0661328921e1ab

http://gstreamer-devel.966125.n4.nabble.com/appsrc-to-filesink-td970865.html

组成这从它们:

#include <string.h> 

#include <gst/gst.h> 

#include <gst/app/gstappsrc.h> 

/* 
* an example application of using appsrc in push mode to create a video file. 
* from buffers we push into the pipeline. 
*/ 

/* Video resolution: 80 x 60 x 4 = 80x60 pixels, 32 bpp (4 bytes per pixel) = 19200 bytes */ 
#define BUFFER_SIZE 19200 

/* 300 frames = 10 seconds of video, since we are going to save at 30fps (se the video_caps next) */ 
#define TOTAL_FRAMES 30000 

#define QUEUED_FRAMES 30 

/* these are the caps we are going to pass through the appsrc */ 
const gchar *video_caps = 
    "video/x-raw,format=RGB,width=80,height=60,bpp=32,endianness=4321,depth=24,red_mask=65280,green_mask=16711680,blue_mask=-16777216,framerate=30/1"; 

typedef struct 
{ 
    GMainLoop *loop; 
    GstElement *pipeline; 
    GstElement *source; 
    guint source_id; 
    guint num_frame; 
} AppData; 

/* This method is called by the idle GSource in the mainloop. We feed 1 buffer 
* of BUFFER_SIZE bytes into appsrc. 
* The ide handler is added to the mainloop when appsrc requests us to start 
* sending data (need-data signal) and is removed when appsrc has enough data 
* (enough-data signal). 
*/ 
static gboolean 
push_buffer (AppData * app) 
{ 
    gpointer raw_buffer; 
    GstBuffer *app_buffer; 
    GstMemory *mem; 
    GstFlowReturn ret; 

    app->num_frame++; 

    if (app->num_frame >= TOTAL_FRAMES) { 
    /* we are EOS, send end-of-stream and remove the source */ 
    g_signal_emit_by_name (app->source, "end-of-stream", &ret); 
    return FALSE; 
    } 

    app_buffer = gst_buffer_new(); 

    mem = gst_allocator_alloc (NULL, BUFFER_SIZE, NULL); 

    gst_buffer_append_memory(app_buffer, mem); 

    gst_buffer_set_size(app_buffer, BUFFER_SIZE); 

    /* Setting the correct timestamp for the buffer is very important, otherwise the 
    * resulting video file won't be created correctly */ 
    GST_BUFFER_TIMESTAMP(app_buffer) = (GstClockTime)((app->num_frame/30.0) * 1e9); 

    /* push new buffer */ 
    g_signal_emit_by_name (app->source, "push-buffer", app_buffer, &ret); 

    gst_buffer_unref(app_buffer); 

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

    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, AppData * app) 
{ 
    if (app->source_id == 0) { 
     g_print ("start feeding at frame %i\n", app->num_frame); 
    app->source_id = g_idle_add ((GSourceFunc) push_buffer, 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, AppData * app) 
{ 
    if (app->source_id != 0) { 
     g_print ("stop feeding at frame %i\n", app->num_frame); 
    g_source_remove (app->source_id); 
    app->source_id = 0; 
    } 
} 

/* called when we get a GstMessage from the pipeline when we get EOS, we 
* exit the mainloop and this testapp. */ 
static gboolean 
on_pipeline_message (GstBus * bus, GstMessage * message, AppData * app) 
{ 
    GstState state, pending; 

    switch (GST_MESSAGE_TYPE (message)) { 
    case GST_MESSAGE_EOS: 
     g_print ("Received End of Stream message\n"); 
     g_main_loop_quit (app->loop); 
     break; 
    case GST_MESSAGE_ERROR: 
     { 
     g_print ("Received error\n"); 

     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_STATE_CHANGED: 
      gst_element_get_state(app->source, &state, &pending, GST_CLOCK_TIME_NONE); 
     /* g_print ("State changed from %i to %i\n", state, pending); */ 
     break; 
     default: 
     break; 
    } 
    return TRUE; 
} 

int 
main (int argc, char *argv[]) 
{ 
    AppData *app = NULL; 
    gchar *string = NULL; 
    GstBus *bus = NULL; 
    GstElement *appsrc = NULL; 

    gst_init (&argc, &argv); 

    app = g_new0 (AppData, 1); 

    app->loop = g_main_loop_new (NULL, FALSE); 

    /* setting up pipeline, we push video data into this pipeline that will 
    * then be recorded to an avi file, encoded with the h.264 codec*/ 
    string = 
     g_strdup_printf ("appsrc is-live=true name=source caps=\"%s\" ! ffmpegcolorspace ! video/x-raw,format=(fourcc)I420,width=80,height=60 ! queue ! videorate ! video/x-raw,format=YUV,framerate=30/1 ! h264enc ! queue ! avimux ! queue ! filesink location=test.avi", 
     video_caps); 
    app->pipeline = gst_parse_launch (string, NULL); 
    g_free (string); 

    if (app->pipeline == NULL) { 
    g_print ("Bad pipeline\n"); 
    return -1; 
    } 

    appsrc = gst_bin_get_by_name (GST_BIN (app->pipeline), "source"); 
    /* configure for time-based format */ 
    g_object_set (appsrc, "format", GST_FORMAT_TIME, NULL); 
    /* setting maximum of bytes queued. default is 200000 */ 
    gst_app_src_set_max_bytes((GstAppSrc *)appsrc, QUEUED_FRAMES * BUFFER_SIZE); 
    /* uncomment the next line to block when appsrc has buffered enough */ 
    /* g_object_set (appsrc, "block", TRUE, NULL); */ 
    app->source = appsrc; 

    /* add watch for messages */ 
    bus = gst_element_get_bus (app->pipeline); 
    gst_bus_add_watch (bus, (GstBusFunc) on_pipeline_message, app); 
    gst_object_unref (bus); 

    /* configure the appsrc, we will push data into the appsrc from the 
    * mainloop */ 
    g_signal_connect (app->source, "need-data", G_CALLBACK (start_feed), app); 
    g_signal_connect (app->source, "enough-data", G_CALLBACK (stop_feed), app); 

    /* 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_print ("Creating movie...\n"); 
    g_main_loop_run (app->loop); 
    g_print ("Done.\n"); 

    gst_app_src_end_of_stream (GST_APP_SRC (app->source)); 

    gst_element_set_state (app->pipeline, GST_STATE_NULL); 

    /* Cleaning up */ 
    gst_object_unref (app->source); 
    gst_object_unref (app->pipeline); 
    g_main_loop_unref (app->loop); 
    g_free (app); 

    return 0; 
} 

的CMakeLists.txt(把FindGStreamer.cmake成模块项目/目录):

cmake_minimum_required(VERSION 2.8.11) 

project(myproject) 

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/modules/") 

find_package(GStreamer 1.0 REQUIRED COMPONENTS 
    app 
    audio 
    video 
) 

add_executable(${PROJECT_NAME} 
    main.c 
) 

target_include_directories(${PROJECT_NAME} PRIVATE ${GSTREAMER_INCLUDE_DIRS}) 
target_include_directories(${PROJECT_NAME} PRIVATE ${GSTREAMER_APP_INCLUDE_DIRS}) 

target_link_libraries(${PROJECT_NAME} 
    ${GSTREAMER_LIBRARIES} 
    ${GSTREAMER_APP_LIBRARIES} 
    ${GSTREAMER_AUDIO_LIBRARIES} 
    ${GSTREAMER_VIDEO_LIBRARIES} 
    glib-2.0 
    gobject-2.0 
) 

实际上,管道为我的计划是:

appsrc is-live=true name=mysource ! flacenc ! oggmux ! filesink location=flac-audio.ogg 

但我试图使实例工作,因为他们是

+0

SO不是免费的调试服务。减少你的问题到[mcve]。 – StoryTeller

+0

@StoryTeller,就是这样。你不能让它变小。这是最基本的gstreamer示例。也许我可能会抛出CMakeLists.txt。 – Velkan

回答

1

--gst-debug-level=2发射是有益的。 正在抱怨caps字符串。

#include <string.h> 

#include <gst/gst.h> 

#include <gst/app/gstappsrc.h> 

/* 
* an example application of using appsrc in push mode to create a file. 
* from buffers we push into the pipeline. 
*/ 

/* S16LE 10ms frame audio */ 
#define BUFFER_SIZE 160 

/* 300 frames = 5 minutes */ 
#define TOTAL_FRAMES 30000 

#define QUEUED_FRAMES 30 

typedef struct 
{ 
    GMainLoop *loop; 
    GstElement *pipeline; 
    GstElement *source; 
    guint source_id; 
    guint num_frame; 
} AppData; 

/* This method is called by the idle GSource in the mainloop. We feed 1 buffer 
* of BUFFER_SIZE bytes into appsrc. 
* The ide handler is added to the mainloop when appsrc requests us to start 
* sending data (need-data signal) and is removed when appsrc has enough data 
* (enough-data signal). 
*/ 
static gboolean 
push_buffer (AppData * app) 
{ 
    gpointer raw_buffer; 
    GstBuffer *app_buffer; 
    GstMemory *mem; 
    GstFlowReturn ret; 

    app->num_frame++; 

    if (app->num_frame >= TOTAL_FRAMES) { 
    /* we are EOS, send end-of-stream and remove the source */ 
    g_signal_emit_by_name (app->source, "end-of-stream", &ret); 
    return FALSE; 
    } 

    app_buffer = gst_buffer_new(); 

    mem = gst_allocator_alloc (NULL, BUFFER_SIZE, NULL); 

    gst_buffer_append_memory(app_buffer, mem); 

    gst_buffer_set_size(app_buffer, BUFFER_SIZE); 

    /* Setting the correct timestamp for the buffer is very important, otherwise the 
    * resulting file won't be created correctly */ 
    GST_BUFFER_TIMESTAMP(app_buffer) = (GstClockTime)((app->num_frame/100.0) * 1e9); 

    /* push new buffer */ 
    g_signal_emit_by_name (app->source, "push-buffer", app_buffer, &ret); 

    gst_buffer_unref(app_buffer); 

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

    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, AppData * app) 
{ 
    if (app->source_id == 0) { 
     g_print ("start feeding at frame %i\n", app->num_frame); 
    app->source_id = g_idle_add ((GSourceFunc) push_buffer, 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, AppData * app) 
{ 
    if (app->source_id != 0) { 
     g_print ("stop feeding at frame %i\n", app->num_frame); 
    g_source_remove (app->source_id); 
    app->source_id = 0; 
    } 
} 

/* called when we get a GstMessage from the pipeline when we get EOS, we 
* exit the mainloop and this testapp. */ 
static gboolean 
on_pipeline_message (GstBus * bus, GstMessage * message, AppData * app) 
{ 
    GstState state, pending; 

    switch (GST_MESSAGE_TYPE (message)) { 
    case GST_MESSAGE_EOS: 
     g_print ("Received End of Stream message\n"); 
     g_main_loop_quit (app->loop); 
     break; 
    case GST_MESSAGE_ERROR: 
     { 
     g_print ("Received error\n"); 

     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_STATE_CHANGED: 
      gst_element_get_state(app->source, &state, &pending, GST_CLOCK_TIME_NONE); 
     /* g_print ("State changed from %i to %i\n", state, pending); */ 
     break; 
     default: 
     break; 
    } 
    return TRUE; 
} 

int 
main (int argc, char *argv[]) 
{ 
    AppData *app = NULL; 
    GstBus *bus = NULL; 
    GstElement *appsrc = NULL; 

    gst_init (&argc, &argv); 

    app = g_new0 (AppData, 1); 

    app->loop = g_main_loop_new (NULL, FALSE); 

    /* setting up pipeline, we push media data into this pipeline that will 
    * then be recorded to a file, encoded with a codec*/ 
    app->pipeline = gst_parse_launch ("appsrc is-live=true name=source caps=audio/x-raw,format=S16LE,rate=8000,channels=1,layout=interleaved ! flacenc ! oggmux ! filesink location=flac-audio.ogg", NULL); 

    if (app->pipeline == NULL) { 
    g_print ("Bad pipeline\n"); 
    return -1; 
    } 

    appsrc = gst_bin_get_by_name (GST_BIN (app->pipeline), "source"); 

    /* setting maximum of bytes queued */ 
    gst_app_src_set_max_bytes((GstAppSrc *)appsrc, QUEUED_FRAMES * BUFFER_SIZE); 

    /* uncomment the next line to block when appsrc has buffered enough */ 
    /* g_object_set (appsrc, "block", TRUE, NULL); */ 
    app->source = appsrc; 

    /* add watch for messages */ 
    bus = gst_element_get_bus (app->pipeline); 
    gst_bus_add_watch (bus, (GstBusFunc) on_pipeline_message, app); 
    gst_object_unref (bus); 

    /* configure the appsrc, we will push data into the appsrc from the 
    * mainloop */ 
    g_signal_connect (app->source, "need-data", G_CALLBACK (start_feed), app); 
    g_signal_connect (app->source, "enough-data", G_CALLBACK (stop_feed), app); 

    /* 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_print ("Creating movie...\n"); 
    g_main_loop_run (app->loop); 
    g_print ("Done.\n"); 

    gst_app_src_end_of_stream (GST_APP_SRC (app->source)); 

    gst_element_set_state (app->pipeline, GST_STATE_NULL); 

    /* Cleaning up */ 
    gst_object_unref (app->source); 
    gst_object_unref (app->pipeline); 
    g_main_loop_unref (app->loop); 
    g_free (app); 

    return 0; 
}