gstreamer appsr和appsink案例
这是一个gstreamer有关appsrc和appsink解码的案例。
·
最近公司codec要用到gstreamer编解码,所以编写了一个gstremer的案例:
这是一个gstreamer有关appsrc和appsink解码的案例。
1、当 push_data(CustomData *data) 返回false后,就再也不会调用它了,why?
2、gstomx hacks配置中,如果没有 “no-disable-outport”,那么默认是关闭的。
#include <gst/app/gstappsrc.h>
#include <stdio.h>
#include <iostream>
#include "gst/gst.h"
#include "gst/video/video.h"
typedef struct _CustomData {
GstElement *pipeline;
GstElement *source;
GstElement *h264parse;
GstElement *omx264dec;
GstElement *convert;
GstElement *sink;
GMainLoop *main_loop;
guint sourceid; /* To control the GSource */
FILE *pFile;
guint size;
FILE *outFile;
} CustomData;
#define W 176
#define H 144
#define MAKE_CAPS(alignment) \
"video/x-h264, " \
"alignment=(string) " alignment \
", " \
"stream-format=(string) byte-stream, " \
"width=(int) 176" \
", " \
"height=(int) 144"
/* The Zynq supports decoding subframes, though we want "au" to be the
* default, so we keep it prepended. This is the only way that it works with
* rtph264depay. */
#define SRC_CAPS MAKE_CAPS("au")
#define SINK_CAPS \
"video/x-raw,format=(string) I420,width=(int) 176, height=(int) 144, pixel-aspect-ratio=1/1"
#define CHUNK_SIZE 2048
/* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
* The idle 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_data(CustomData *data) {
GstBuffer *buffer;
GstFlowReturn ret;
GstMapInfo map;
guint8 *raw;
if (data->size == 0) {
/* We got eof, send eos */
buffer = gst_buffer_new_and_alloc(0);
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
map.data = NULL;
map.size = 0;
g_signal_emit_by_name(data->source, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
/* We got some error, stop sending data */
return FALSE;
}
gst_buffer_unref(buffer);
g_print("last NUll data\n");
ret = gst_app_src_end_of_stream(GST_APP_SRC(data->source));
g_print("eos returned %d at %d\n", ret, __LINE__);
return FALSE;
}
/* Create a new empty buffer */
buffer = gst_buffer_new_and_alloc(data->size);
gst_buffer_map(buffer, &map, GST_MAP_WRITE);
raw = (guint8 *)map.data;
gint lSize = 0;
data->size > CHUNK_SIZE ? lSize = CHUNK_SIZE : lSize = data->size;
gint result = fread(raw, 1, data->size, data->pFile);
data->size -= result;
g_print("read size=%d\n", result);
gst_buffer_unmap(buffer, &map);
/* Push the buffer into the appsrc */
g_signal_emit_by_name(data->source, "push-buffer", buffer, &ret);
if (ret != GST_FLOW_OK) {
/* We got some error, stop sending data */
return FALSE;
}
/* Free the buffer now that we are done with it */
gst_buffer_unref(buffer);
return TRUE;
}
/* This signal callback triggers when appsrc needs data. Here, we add an idle handler
* to the mainloop to start pushing data into the appsrc */
static void start_feed(GstElement *source, guint size, CustomData *data) {
if (data->sourceid == 0) {
g_print("Start feeding\n");
data->sourceid = g_idle_add((GSourceFunc)push_data, data);
}
}
/* This callback triggers when appsrc has enough data and we can stop sending.
* We remove the idle handler from the mainloop */
static void stop_feed(GstElement *source, CustomData *data) {
if (data->sourceid != 0) {
g_print("Stop feeding\n");
g_source_remove(data->sourceid);
data->sourceid = 0;
}
}
static void eos(GstElement *source, CustomData *data) { g_print("this is appsrc eos\n"); }
/* The appsink has received a buffer */
static GstFlowReturn new_sample(GstElement *sink, CustomData *data) {
GstSample *sample;
/* Retrieve the buffer */
g_signal_emit_by_name(sink, "pull-sample", &sample);
if (sample) {
/* The only thing we do in this example is print a * to indicate a received buffer */
GstBuffer *buf = gst_sample_get_buffer(sample);
GstMapInfo map;
guint8 *raw;
gst_buffer_map(buf, &map, GST_MAP_READ);
// g_print("buf size=%d\n", map.size);
raw = (guint8 *)map.data;
fwrite(raw, 1, map.size, data->outFile);
fflush(data->outFile);
gst_sample_unref(sample);
return GST_FLOW_OK;
}
return GST_FLOW_ERROR;
}
/* This function is called when an error message is posted on the bus */
static void error_cb(GstBus *bus, GstMessage *msg, CustomData *data) {
GError *err;
gchar *debug_info;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &err, &debug_info);
g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error(&err);
g_free(debug_info);
break;
case GST_MESSAGE_EOS:
g_print("End-Of-Stream reached.\n");
break;
default:
/* We should not reach here because we only asked for ERRORs and EOS
*/
g_printerr("Unexpected message received.\n");
break;
}
// gst_message_unref(msg);
g_main_loop_quit(data->main_loop);
}
int main(int argc, char *argv[]) {
CustomData data;
memset(&data, 0, sizeof(data));
GstBus *bus;
GstStateChangeReturn ret;
char const *infile = "./305.264";
data.pFile = fopen(infile, "rb+");
if (data.pFile == NULL) {
perror("Error opening file");
return 1;
}
fseek(data.pFile, 0, SEEK_END);
data.size = ftell(data.pFile);
rewind(data.pFile);
g_print("file [%s]size:%d\n", infile, data.size);
data.outFile = fopen("./176-144.yuv", "wb+");
if (data.outFile == NULL) {
perror("Error opening file");
return 1;
}
/* Initialize GStreamer */
gst_init(&argc, &argv);
/* Create the elements */
data.source = gst_element_factory_make("appsrc", "app-source");
data.h264parse = gst_element_factory_make("h264parse", "h264-parse");
data.omx264dec = gst_element_factory_make("omxh264dec", "decodecr-omx64");
data.convert = gst_element_factory_make("videoconvert", "color-convert");
data.sink = gst_element_factory_make("appsink", "app-sink");
/* Create the empty pipeline */
data.pipeline = gst_pipeline_new("test-pipeline");
if (!data.pipeline || !data.source || !data.sink || !data.h264parse || !data.omx264dec ||
!data.convert) {
g_printerr("Not all elements could be created.\n");
return -1;
}
/* Configure appsrc */
GstCaps *src_caps = NULL;
src_caps = gst_caps_from_string(SRC_CAPS);
g_object_set(data.source, "caps", src_caps, NULL);
g_object_set(data.source, "stream-type", GST_APP_STREAM_TYPE_STREAM, NULL);
g_signal_connect(data.source, "need-data", G_CALLBACK(start_feed), &data);
g_signal_connect(data.source, "enough-data", G_CALLBACK(stop_feed), &data);
g_signal_connect(data.source, "end-of-stream", G_CALLBACK(eos), &data);
gst_caps_unref(src_caps);
/* Configure appsink */
GstCaps *sink_caps = NULL;
sink_caps = gst_caps_from_string(SINK_CAPS);
g_object_set(data.sink, "emit-signals", TRUE, "caps", sink_caps, NULL);
g_signal_connect(data.sink, "new-sample", G_CALLBACK(new_sample), &data);
gst_caps_unref(sink_caps);
/* Build the pipeline */
gst_bin_add_many(GST_BIN(data.pipeline), data.source, data.h264parse, data.omx264dec,
data.convert, data.sink, nullptr);
if (gst_element_link_many(data.source, data.h264parse, data.omx264dec, data.convert, data.sink,
nullptr) != TRUE) {
g_printerr("Elements could not be linked.\n");
gst_object_unref(data.pipeline);
return -1;
}
bus = gst_element_get_bus(data.pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect(G_OBJECT(bus), "message::error", (GCallback)error_cb, &data);
g_signal_connect(G_OBJECT(bus), "message::eos", (GCallback)error_cb, &data);
/* Start playing */
ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref(data.pipeline);
return -1;
}
/* Create a GLib Main Loop and set it to run */
data.main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(data.main_loop);
/* Free resources */
gst_element_set_state(data.pipeline, GST_STATE_NULL);
gst_object_unref(bus);
gst_object_unref(data.pipeline);
fclose(data.pFile);
fclose(data.outFile);
return 0;
}
下面是cmake文件:
# CMake 最低版本号要求
cmake_minimum_required (VERSION 3.5)
# 项目信息
project (Gstreamer-Demo1)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -fpermissive")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall -fpermissive")
set(root_path /workspace/depends)
#dependencies
set(ENV{PKG_CONFIG_PATH} "${root_path}/libgstreamer/lib/x86_64-linux-gnu/pkgconfig")
find_package(PkgConfig)
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
message(STATUS "=== GSTREAMER_LIBRARIES: ${GSTREAMER_LIBRARIES}")
message(STATUS "=== GSTREAMER_INCLUDE_DIRS: ${GSTREAMER_INCLUDE_DIRS}")
message(STATUS "=== GSTREAMER_LIBRARY_DIRS: ${GSTREAMER_LIBRARY_DIRS}")
include_directories(${GSTREAMER_INCLUDE_DIRS} )
link_directories(${GSTREAMER_LIBRARY_DIRS})
set(SOURCES main.cpp)
# 指定生成目标
add_executable(Demo ${SOURCES})
target_link_libraries(Demo ${GSTREAMER_LIBRARIES} gstvideo-1.0 gstapp-1.0)
更多推荐
已为社区贡献4条内容
所有评论(0)