2017-03-20 7 views
1

v4l2src 디스플레이 및 녹음을위한 코드를 작성했습니다. tee에서 브랜치를 지우면서 filesink에 EoS 보내기

   /[queue] ! [videosink] 
v4l2src ! tee ! 
       \ [queue] ! [filesink] 

은 현재 내가 함께 + 기록을 표시 할 수 있어요, 또한 동적으로 시작하고 (시작/정지에 대한 Ctrl + C의 SIGINT 핸들러를 사용하여)의 뜻에서 레코드 분기를 중지 : 같은 내 파이프 라인이 보인다. this 답에 @ thiagoss의 조언, 그리고 this의 기사를 사용했습니다.

질문 :

내가 직면하고있는 유일한 문제는 보내는 EOS은 링크 해제에 지점을 filesink합니다. 어떤 요소에 gst_element_send_event(-->?<--, gst_event_new_eos()); 이벤트를 보내겠습니까? 분기가 연결 해제 되었기 때문에 전체 파이프 라인으로 보낼 수 없습니다. 2. 내가 할지라도, 그것은 비디오 링크를 닫을 것입니다.

내가 시도한 것 : mp4mux를 제거하고 h264로 인코딩 된 비디오를 저장하면 gst-playbin을 사용하여 비디오를 볼 수 있습니다. 즉, 브랜치 생성 및 연결 해제가 올바르게 수행되고 있음을 의미합니다.

다음은 제 코드입니다.

#include <string.h> 
#include <gst/gst.h> 
#include <signal.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 

// v4l2src ! tee name=t t. ! x264enc ! mp4mux ! filesink location=/home/rish/Desktop/okay.264 t. ! videoconvert ! autovideosink 

static GMainLoop *loop; 
static GstElement *pipeline, *src, *tee, *encoder, *muxer, *filesink, *videoconvert, *videosink, *queue_record, *queue_display; 
static GstBus *bus; 
static GstPad *teepad; 
static gboolean recording = FALSE; 
static gint counter = 0; 

static gboolean 
message_cb (GstBus * bus, GstMessage * message, gpointer user_data) 
{ 
switch (GST_MESSAGE_TYPE (message)) { 
case GST_MESSAGE_ERROR:{ 
    GError *err = NULL; 
    gchar *name, *debug = NULL; 

    name = gst_object_get_path_string (message->src); 
    gst_message_parse_error (message, &err, &debug); 

    g_printerr ("ERROR: from element %s: %s\n", name, err->message); 
    if (debug != NULL) 
    g_printerr ("Additional debug info:\n%s\n", debug); 

    g_error_free (err); 
    g_free (debug); 
    g_free (name); 

    g_main_loop_quit (loop); 
    break; 
} 
case GST_MESSAGE_WARNING:{ 
    GError *err = NULL; 
    gchar *name, *debug = NULL; 

    name = gst_object_get_path_string (message->src); 
    gst_message_parse_warning (message, &err, &debug); 

    g_printerr ("ERROR: from element %s: %s\n", name, err->message); 
    if (debug != NULL) 
    g_printerr ("Additional debug info:\n%s\n", debug); 

    g_error_free (err); 
    g_free (debug); 
    g_free (name); 
    break; 
} 
case GST_MESSAGE_EOS:{ 
    g_print ("Got EOS\n"); 
    g_main_loop_quit (loop); 
    gst_element_set_state (pipeline, GST_STATE_NULL); 
    g_main_loop_unref (loop); 
    gst_object_unref (pipeline); 
    exit(0); 
    break; 
} 
default: 
    break; 
} 

return TRUE; 
} 

static GstPadProbeReturn unlink_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { 
g_print("Unlinking..."); 
GstPad *sinkpad; 
sinkpad = gst_element_get_static_pad (queue_record, "sink"); 
gst_pad_unlink (teepad, sinkpad); 
gst_object_unref (sinkpad); 

gst_element_send_event(filesink, gst_event_new_eos()); 

sleep(1); 
gst_bin_remove(GST_BIN (pipeline), queue_record); 
gst_bin_remove(GST_BIN (pipeline), encoder); 
// gst_bin_remove(GST_BIN (pipeline), muxer); 
gst_bin_remove(GST_BIN (pipeline), filesink); 

gst_element_set_state(queue_record, GST_STATE_NULL); 
gst_element_set_state(encoder, GST_STATE_NULL); 
// gst_element_set_state(muxer, GST_STATE_NULL); 
gst_element_set_state(filesink, GST_STATE_NULL); 

gst_object_unref(queue_record); 
gst_object_unref(encoder); 
// gst_object_unref(muxer); 
gst_object_unref(filesink); 

gst_element_release_request_pad (tee, teepad); 
gst_object_unref (teepad); 

g_print("Unlinked\n"); 

return GST_PAD_PROBE_REMOVE; 
} 

void stopRecording() { 
    g_print("stopRecording\n"); 
    gst_pad_add_probe(teepad, GST_PAD_PROBE_TYPE_IDLE, unlink_cb, NULL, (GDestroyNotify) g_free); 
    recording = FALSE; 
} 

void startRecording() { 
g_print("startRecording\n"); 
GstPad *sinkpad; 
GstPadTemplate *templ; 

templ = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(tee), "src_%u"); 
teepad = gst_element_request_pad(tee, templ, NULL, NULL); 
queue_record = gst_element_factory_make("queue", "queue_record"); 
encoder = gst_element_factory_make("x264enc", NULL); 
// muxer = gst_element_factory_make("mp4mux", NULL); 
filesink = gst_element_factory_make("filesink", NULL); 
char *file_name = (char*) malloc(100*sizeof(char)); 
sprintf(file_name, "/home/rish/Desktop/rec%d.mp4", counter++); 
g_print(file_name); 
g_object_set(filesink, "location", file_name, NULL); 
g_object_set(encoder, "tune", 4, NULL); 
free(file_name); 

gst_bin_add_many(GST_BIN(pipeline), gst_object_ref(queue_record), gst_object_ref(encoder), gst_object_ref(filesink), NULL); 
gst_element_link_many(queue_record, encoder, filesink, NULL); 

gst_element_sync_state_with_parent(queue_record); 
gst_element_sync_state_with_parent(encoder); 
// gst_element_sync_state_with_parent(muxer); 
gst_element_sync_state_with_parent(filesink); 

sinkpad = gst_element_get_static_pad(queue_record, "sink"); 
gst_pad_link(teepad, sinkpad); 
gst_object_unref(sinkpad); 

recording = TRUE; 
} 

int sigintHandler(int unused) { 
g_print("You ctrl-c!\n"); 
if (recording) 
    stopRecording(); 
else 
    startRecording(); 
return 0; 
} 

int main(int argc, char *argv[]) 
{ 
signal(SIGINT, sigintHandler); 
gst_init (&argc, &argv); 

pipeline = gst_pipeline_new(NULL); 
src = gst_element_factory_make("v4l2src", NULL); 
tee = gst_element_factory_make("tee", "tee"); 
queue_display = gst_element_factory_make("queue", "queue_display"); 
videoconvert = gst_element_factory_make("videoconvert", NULL); 
videosink = gst_element_factory_make("autovideosink", NULL); 

if (!pipeline || !src || !tee || !videoconvert || !videosink || !queue_display) { 
    g_error("Failed to create elements"); 
    return -1; 
} 

gst_bin_add_many(GST_BIN(pipeline), src, tee, queue_display, videoconvert, videosink, NULL); 
if (!gst_element_link_many(src, tee, NULL) 
    || !gst_element_link_many(tee, queue_display, videoconvert, videosink, NULL)) { 
    g_error("Failed to link elements"); 
    return -2; 
} 

startRecording(); 
loop = g_main_loop_new(NULL, FALSE); 

bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline)); 
gst_bus_add_signal_watch(bus); 
g_signal_connect(G_OBJECT(bus), "message", G_CALLBACK(message_cb), NULL); 
gst_object_unref(GST_OBJECT(bus)); 

gst_element_set_state(pipeline, GST_STATE_PLAYING); 

g_print("Starting loop\n"); 
g_main_loop_run(loop); 

return 0; 
} 

답변

3

제대로 작업을 완료 할 수 있으며 그들은 또한 헤더 부분을 작성하여 파일을 마무리해야하는 먹서에게 전달되도록 당신은 인코더로 전송해야하는 그들은 단지 수 끝에서 씁니다.

또한 수면을 제거하십시오. 파일 싱크가 모두 처리되었으며 안전하게 제거 할 수 있도록 EOS 메시지를 게시했는지 확인해야합니다. 파이프 라인에 message-forward을 사용하도록 설정해야 할 수도 있습니다. 그렇지 않으면 모든 싱크가 EOS를 게시 할 때까지 EOS 메시지를 보관합니다 (videosink로 인해 발생하지 않음).

+0

고맙습니다. @ thiagoss! 엔코더에 EOS를 보내면 파일이 올바르게 저장됩니다. 예, sleep()은 해킹이었습니다. 특정 분기에 대한 EOS 콜백을 얻는 방법을 알지 못했습니다. '메시지 전달'을 들여다 볼 것입니다. 다시 한 번 감사드립니다! –

0

EOS를 무시하고 사용자 지정 메시지로 변환하려면 재정의 된 handle_message (How to override handle_message in GstBin?)이있는 별도의 저장소에 filesink가 있습니다.

초기 EOS는 해당 bin의 ghostpad로 전송됩니다. 해당 패드는 인코더에 연결됩니다 (해당 저장소에는 인코더, 멀티플렉서 및 파일 공유가 포함됨).