首页 > 解决方案 > 从 Gstreamer appsinnk 保存 jpeg 的最佳方法

问题描述

我有一个 USB 摄像头生成 MJPEG 流,我的应用程序正在读取它。我想保存图像(JPEG)。我试图通过创建从应用程序到图像的第二个管道来做到这一点,但我是第一个承认我不知道如何正确终止这样一个管道的人。该实现在平均拍摄 3 张图像后使应用程序崩溃。如果可能,我不希望对图像进行重新解码。是否有与创建第二个管道/解码图像不同的方法来保存图像?

我目前的实现是:

static GstFlowReturn new_sample_jpeg(GstElement * elt, MyStruct *data){

    GstSample *sample;
    GstBuffer *buffer;
    GstMemory *memory;
    GstMapInfo info;
    GstFlowReturn ret = GST_FLOW_OK;
    // get the sample from appsink
    sample = gst_app_sink_pull_sample (GST_APP_SINK (elt));
    //if recording, send the sample to recording sink
    if (data->saveVideo) addSampleFromAppsinkVideo(gst_sample_copy(sample));
    buffer = gst_sample_get_buffer (sample);

    if (buffer != NULL){
 memory = gst_buffer_get_memory (buffer, 0);

    if (memory != NULL) {
        //now all data are image data. If image wanted->image save!
        if (data->saveImage) saveSampleFromAppsinkJpeg(gst_sample_copy(sample));
        ...

        gst_memory_unref(memory);
    } else {
        std::cerr << "sample_from_sink(): ERROR memory" << std::endl;
    }
} else {
    std::cerr << "sample_from_sink(): ERROR buffer " << gst_buffer_get_size(buffer) << std::endl;
}
gst_sample_unref (sample);
return ret;
}



int saveSampleFromAppsinkJpeg( GstSample *sample){

//create the pipeline
GstStateChangeReturn ret;

GstElemenent *source = gst_element_factory_make ("appsrc", "appsrc_capture");
GstElemenent *sink = gst_element_factory_make ("multifilesink", "sink_capture");

g_object_set (sink, "location", "some/path.jpg", NULL);

GstElemenent *pipeline = gst_pipeline_new ("pipeline_img");

if (!pipeline || !source || !sink) {
  g_printerr ("Not all elements could be created.\n");
  return false;
}

GstCaps *caps;
caps = gst_sample_get_caps(sample);

gst_app_src_set_caps(GST_APP_SRC(source), caps);
gst_app_src_set_duration(GST_APP_SRC(source), GST_TIME_AS_MSECONDS(80));
gst_app_src_set_stream_type(GST_APP_SRC(source), GST_APP_STREAM_TYPE_STREAM);
gst_app_src_set_latency(GST_APP_SRC(source), -1, 0);

gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
gst_caps_unref (caps);
if (gst_element_link_many(source, sink, NULL) != TRUE) {
  g_printerr ("Elements could not be linked.\n");
  gst_object_unref (pipeline);
return -1;
}

ret = gst_element_set_state (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 (pipeline);
  return -1;
}

//push the image in the pipeline
GstFlowReturn status = GstFlowReturn::GST_FLOW_OK;
status = gst_app_src_push_sample(GST_APP_SRC(source),sample);
if (status !=  GstFlowReturn::GST_FLOW_OK) g_printerr ("Sample for saving image not pushed: code %d.\n", status);
usleep(500000); // not clean. But how to do this better?
status = gst_app_src_end_of_stream(GST_APP_SRC(source));
if (status !=  GstFlowReturn::GST_FLOW_OK) g_printerr ("EOS for saving image not pushed %d \n", status);
usleep(500000); // not clean. But how to do this better?

//end the pipeline
GstMessage *EndMessage = gst_message_new_eos(&pipeline->object);
gst_bus_post(pipeline->bus, EndMessage);
gst_element_send_event(pipeline, gst_event_new_eos());

/* Free resources */
if (EndMessage != NULL) gst_message_unref (EndMessage);
status = gst_app_src_end_of_stream(GST_APP_SRC(source));

//end the pipeline
usleep(500000); // not clean. But how to do this better?
gst_element_set_state (pipeline, GST_STATE_NULL);
GstState currentState = GST_STATE_READY;
GstClockTime timeout = 50;
uint8_t safetyCounter = 255;
do{
    gst_element_get_state(pipeline, &currentState, NULL,timeout );
    if (safetyCounter-- == 0){ //ok, something is seqiously broken here
        break;
    }
    usleep(10000);
} while (currentState != GST_STATE_NULL);

gst_object_unref (pipeline);
gst_sample_unref(sample);
return 1;

}

标签: cjpeggstreamermjpeg

解决方案


所以最后我只是使用uvc库(https://github.com/libuvc/libuvc)将mjpeg解码为rgb,然后我用jpeglib将它编码为jpeg。相当浪费,但工作。


推荐阅读