流媒体。将 appsink 写入 filesink

Gstreamer. Write appsink to filesink

我已经为 appsrc 编写了一个代码到 appsink 并且它可以工作。我看到了实际的缓冲区。它以 H264(vpuenc=avc) 编码。现在我想把它保存在一个文件(filesink)中。我如何处理它?

应用程序:

int main(int argc, char *argv[]) {

gst_init (NULL, NULL);

GstElement *pipeline, *sink;
gchar *descr;
GError *error = NULL;
GstAppSink *appsink;

descr = g_strdup_printf ( 
    "mfw_v4lsrc device=/dev/video1 capture_mode=0 !  "  // grab from mipi camera
    "ffmpegcolorspace ! vpuenc codec=avc ! "
    "appsink name=sink"
); 
pipeline = gst_parse_launch (descr, &error);
if (error != NULL) {
    g_print ("could not construct pipeline: %s\n", error->message);
    g_error_free (error);
    exit (-1);
}

gst_element_set_state(pipeline, GST_STATE_PAUSED);
sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");
appsink = (GstAppSink *) sink;
gst_app_sink_set_max_buffers ( appsink, 2); // limit number of buffers queued
gst_app_sink_set_drop( appsink, true ); // drop old buffers in queue when full

gst_element_set_state (pipeline, GST_STATE_PLAYING);


int i = 0;
while( !gst_app_sink_is_eos(appsink) )
{

    GstBuffer *buffer = gst_app_sink_pull_buffer(appsink);
    uint8_t* data = (uint8_t*)GST_BUFFER_DATA(buffer);
    uint32_t size = GST_BUFFER_SIZE(buffer);

    gst_buffer_unref(buffer);
}
return 0; }

更简单的选项是直接在 appsink 本身中写入文件,即当缓冲区完成写入文件并确保在 eos 上关闭它时收到回调。

希望对您有所帮助。

在这种情况下,您无需编写自己的 while 循环。您注册回调并等待缓冲区 (GStreamer 0.10) 到达。如果您使用的是 GStreamer 1.0,则使用样本而不是缓冲区。与缓冲区相比,样本是一个巨大的痛苦,但是哦,好吧。

注册回调:

GstAppSinkCallbacks* appsink_callbacks = (GstAppSinkCallbacks*)malloc(sizeof(GstAppSinkCallbacks));
appsink_callbacks->eos = NULL;
appsink_callbacks->new_preroll = NULL;
appsink_callbacks->new_sample = app_sink_new_sample;
gst_app_sink_set_callbacks(GST_APP_SINK(appsink), appsink_callbacks, (gpointer)pointer_to_data_passed_to_the_callback, free);

你的回电:

GstFlowReturn app_sink_new_sample(GstAppSink *sink, gpointer user_data) {
  prog_data* pd = (prog_data*)user_data;

  GstSample* sample = gst_app_sink_pull_sample(sink);

  if(sample == NULL) {
    return GST_FLOW_ERROR;
  }

  GstBuffer* buffer = gst_sample_get_buffer(src);

  GstMemory* memory = gst_buffer_get_all_memory(buffer);
  GstMapInfo map_info;

  if(! gst_memory_map(memory, &map_info, GST_MAP_READ)) {
    gst_memory_unref(memory);
    gst_sample_unref(sample);
    return GST_FLOW_ERROR;
  }

  //render using map_info.data

  gst_memory_unmap(memory, &map_info);
  gst_memory_unref(memory);
  gst_sample_unref(sample);

  return GST_FLOW_OK;
}

您可以保持 while 循环不变——使用 gst_app_sink_is_eos()——但一定要在其中休眠。大多数时候我使用类似下面的东西:

GMainLoop* loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
g_main_loop_unref(loop);

注意:除非您需要对数据做一些特殊的事情,否则您可以直接使用 "filesink" 元素。

如果如评论中所述,您真正想知道的是如何在 GStreamer 中制作网络视频流,您可能应该关闭此问题,因为您走错了路。您不需要为此使用 appsink 或 filesink。您需要研究的是与 RTP、RTSP、RTMP、MPEGTS 甚至 MJPEG(如果您的图像尺寸足够小)相关的 GStreamer 元素。

这里有两个基本的 send/receive 视频流管道:

gst-launch-0.10 v4l2src ! ffmpegcolorspace ! videoscale ! video/x-raw-yuv,width=640,height=480 ! vpuenc ! h264parse ! rtph264pay ! udpsink host=localhost port=5555

gst-launch-0.10 udpsrc port=5555 ! application/x-rtp,encoding-name=H264,payload=96 ! rtph264depay ! h264parse ! ffdec_h264 ! videoconvert ! ximagesink