我想将音频缓冲区写入文件。
问题是该文件始终为空或应用程序会立即停止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放入项目的modules /目录中):
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 :(得分: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;
}