В Gstreamer при воспроизведении конвейера в iOS 8 и после ввода фона и возврата переднего плана конвейер не работает:(?
-На самом деле я скачал образец учебника для gstreamer по ссылке,
http://cgit.freedesktop.org/~slomo/gst-sdk-tutorials/
мерзавец://people.freedesktop.org/~slomo/gst-sdk-tutorials
Теперь я изменил следующий код в учебнике 3,
-(void) app_function { GstBus *bus; GSource *bus_source; GError *error = NULL; GST_DEBUG ("Creating pipeline"); pipeline = gst_pipeline_new ("e-pipeline"); /* Create our own GLib Main Context and make it the default one */ context = g_main_context_new (); g_main_context_push_thread_default(context); /* Build pipeline */ // pipeline = gst_parse_launch("videotestsrc ! warptv ! videoconvert ! autovideosink", &error); source = gst_element_factory_make("udpsrc", "source"); g_object_set( G_OBJECT ( source), "port", 8001, NULL ); GstCaps *caps; caps = gst_caps_new_simple ("application/x-rtp", "encoding-name", G_TYPE_STRING, "H264", "payload", G_TYPE_INT, 96, "clock-rate", G_TYPE_INT, 90000, NULL); g_object_set (source, "caps", caps, NULL); rtp264depay = gst_element_factory_make ("rtph264depay", "rtph264depay"); h264parse = gst_element_factory_make ("h264parse", "h264parse"); vtdec = gst_element_factory_make ("vtdec", "vtdec"); glimagesink = gst_element_factory_make ("glimagesink", "glimagesink"); gst_bin_add_many (GST_BIN(pipeline), source, rtp264depay, h264parse, vtdec, glimagesink, NULL); if (error) { gchar *message = g_strdup_printf("Unable to build pipeline: %s", error->message); g_clear_error (&error); [self setUIMessage:message]; g_free (message); return; } /* Set the pipeline to READY, so it can already accept a window handle */ gst_element_set_state(pipeline, GST_STATE_READY); video_sink = gst_bin_get_by_interface(GST_BIN(pipeline), GST_TYPE_VIDEO_OVERLAY); if (!video_sink) { GST_ERROR ("Could not retrieve video sink"); return; } gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), (guintptr) (id) ui_video_view); /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */ bus = gst_element_get_bus (pipeline); bus_source = gst_bus_create_watch (bus); g_source_set_callback (bus_source, (GSourceFunc) gst_bus_async_signal_func, NULL, NULL); g_source_attach (bus_source, context); g_source_unref (bus_source); g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, (__bridge void *)self); g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, (__bridge void *)self); gst_object_unref (bus); /* Create a GLib Main Loop and set it to run */ GST_DEBUG ("Entering main loop..."); main_loop = g_main_loop_new (context, FALSE); [self check_initialization_complete]; g_main_loop_run (main_loop); GST_DEBUG ("Exited main loop"); g_main_loop_unref (main_loop); main_loop = NULL; /* Free resources */ g_main_context_pop_thread_default(context); g_main_context_unref (context); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); return;
}
-Теперь я запускаю приложение в ipad, и приложение начинает играть.
- Сейчас я вхожу в фоновый режим и возвращаюсь на передний план. Потоковые обновления Gstreamer не видны в пользовательском интерфейсе, но при использовании сети xcode я мог видеть получение пакетов....:(
Заранее спасибо....iOS GEEKS....
2 ответа
Обновление: заставить работать UDP.
После дальнейшего изучения я получил потоковую передачу UDP h264 для работы на linux (ПК x86), но принцип должен быть таким же на IOS (в частности, avdec_h264 (используется на ПК) должен быть заменен на vtdec).
Основные различия между TCP и UDP конвейерами:
Сторона сервера:
- IP: первый элемент, который смутил меня между сторонами сервера UDP и TCP: на сервере UDP IP-адрес, указанный в элементе udpsink, является IP-адресом на стороне клиента, т.е.
gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=$CLIENTIP port=5000
В то время как на стороне сервера TCP, IP является тем на стороне сервера (параметр хоста на tcpserversink), т.е.gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=$SERVERIP port=5000
- Полезная нагрузка / формат видеопотока. Чтобы клиент мог определить формат и размер кадров, сторона TCP-сервера использует в своем конвейере gdppay, элемент payloader. На стороне клиента противоположный элемент, de-payloader, используется gdpdepay для того, чтобы иметь возможность читать принятые кадры. т.е.
gst-launch-1.0 -v fdsrc! h264parse! rtph264pay config-interval = 1 pt = 96! gdppay! хост tcpserversink = порт $SERVERIP =5000
Серверная часть UDP не использует элемент gdpay, она оставляет клиентскую сторону для использования CAPS на своей udpsink, см. Различия в клиентской части ниже.
Сторона клиента
- IP: UDP- клиенту НЕ требуется указывать IP-адрес. В то время как стороне клиента TCP нужен IP-адрес сервера (параметр хоста в tcpclientsrc), т.е.
gst-launch-1.0 -v tcpclientsrc host=$SERVERIP port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false enable-last-buffer=false
- Полезная нагрузка / формат видеопотока: как упомянуто в предыдущем параграфе, сторона сервера TCP использует payloader gdppay, в то время как сторона клиента использует de-payloader для распознавания формата и размера кадров.
Вместо этого UDP- клиент должен явно указать его, используя caps для своего элемента udpsrc, т.е.CAPS='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96'
gst-launch-1.0 -v udpsrc port =5000 caps = $ CAPS! rtph264depay! avdec_h264! видеоконвертер! autovideosink sync=false enable-last-buffer=false`
Как указать прописные буквы: это немного странно, но работает: запустите ваш UDP-сервер, с подробной опцией -v iegst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=$CLIENTIP port=5000
Вы получите следующий журнал:
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
/GstPipeline:pipeline0/GstH264Parse:h264parse0.GstPad:src: caps = video/x-h264, width=(int)1280, height=(int)720, parsed=(boolean)true, stream-format=(string)avc, alignment=(string)au, codec_data=(buffer)01640028ffe1000e27640028ac2b402802dd00f1226a01000428ee1f2c
/GstPipeline:pipeline0/GstRtpH264Pay:rtph264pay0.GstPad:src: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)"J2QAKKwrQCgC3QDxImo\=\,KO4fLA\=\=", payload=(int)96, ssrc=(uint)3473549335, timestamp-offset=(uint)257034921, seqnum-offset=(uint)12956
/GstPipeline:pipeline0/GstUDPSink:udpsink0.GstPad:sink: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, sprop-parameter-sets=(string)"J2QAKKwrQCgC3QDxImo\=\,KO4fLA\=\=", payload=(int)96, ssrc=(uint)3473549335, timestamp-offset=(uint)257034921, seqnum-offset=(uint)12956
/GstPipeline:pipeline0/GstRtpH264Pay:rtph264pay0.GstPad:sink: caps = video/x-h264, width=(int)1280, height=(int)720, parsed=(boolean)true, stream-format=(string)avc, alignment=(string)au, codec_data=(buffer)01640028ffe1000e27640028ac2b402802dd00f1226a01000428ee1f2c
/GstPipeline:pipeline0/GstRtpH264Pay:rtph264pay0: timestamp = 257034921
/GstPipeline:pipeline0/GstRtpH264Pay:rtph264pay0: seqnum = 12956
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
Теперь скопируйте заглавные буквы, начинающиеся с заглавных букв = application/x-rtp Это тот, который определяет формат потока rtp. Насколько я знаю тот, который действительно является обязательным, чтобы заставить UDP-клиента распознавать содержимое потока rtp и затем инициализировать воспроизведение.
Чтобы обернуть это и избежать путаницы, найдите полные примеры командной строки ниже, используя raspivid с Raspberry pi. если вы хотите попробовать это (на Linux)
UDP
- Сервер:
raspivid -t 0 -w 1280 -h 720 -fps 25 -b 2500000 -o - | gst-launch-1.0 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=$CLIENTIP port=5000
- Клиент:
CAPS='application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96' gst-launch-1.0 -v udpsrc port=5000 caps=$CAPS ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false enable-last-buffer=false
TCP
Сервер:
raspivid -t 0 -w 1280 -h 720 -fps 25 -b 2500000 -o - | gst-launch-0.10 -v fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=$SERVERIP port=5000
Клиент:
gst-launch-1.0 -v tcpclientsrc host=$SERVERIP port=5000 ! gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink sync=false enable-last-buffer=false
Примечание: Raspivid можно легко заменить простым файлом h264, используя cat, т.е. cat myfile.h264 | gst-launch...
Недавно я пытался заставить работать потоковую трансляцию с RaspberryPi на IOS8, используя аппаратное декодирование h264, используя API Apple VideoToolBox через плагин vtdec gstreamer.
Я посмотрел на многие учебники, а именно из Braincorp ( https://github.com/braincorp/gstreamer_ios_tutorial)
и Себастьян Дрёге: http://cgit.freedesktop.org/~slomo/gst-sdk-tutorials/
Я получил последний для работы, учебник 3 изменен:
Конвейер сервера на RaspberryPi с использованием pi Camera и Raspivid + gstreamer:
распивид -t 0 -w 1280 -h 720 -fps 25 -b 2500000 -p 0,0,640,480 -o - | gst-launch-0.10 -v fdsrc! h264parse! rtph264pay config-interval = 1 pt = 96! gdppay! tcpserversink host = ServerIPRaspberryPi port = any_port_on_Rpiклиентский конвейер одно устройство IOS 8:
tcpclientsrc host = ServerIPRaspberryPi port = any_port_on_Rpi! gdpdepay! rtph264depay! h264parse! Вторк! glimagesink
или то же самое с glimagesink вместо автовидеоинк.
Это решение работает, и несколько клиентов могут использоваться одновременно. Я пытался заставить работать udpsink вместо tcpserversink, но не повезло, пока это не сработало.
=== ВАЖНО ===
Кроме того, фабричный способ использования gst_element_factory_make() + gst_bin_add_many (GST_BIN(конвейер), ...) никогда не работал. Вместо этого я использовал метод pipe = gst_parse_launch(...).
Так что в нашем случае на стороне клиента IOS:
pipe = gst_parse_launch("хост tcpclientsrc =172.19.20.82 порт =5000! gdpdepay! rtph264depay! h264parse! vtdec! autovideosink", &error);
Возможная причина: есть страница, документирующая различия и способ переноса кода из gstreamer 0.10 и 1.0: http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-porting-1.0.html
Мы отметили, что при использовании "фабричного метода" отсутствовали различные элементы конвейера в зависимости от того, использовали ли мы gstreamer 1.0 или 0.1, то есть trph264depay или avdec_h264 (используется на других платформах, например на стороне клиента linux), для декодирования h264 вместо специфического для IOS vtdec).
Мы едва могли собрать все элементы вместе, используя метод Factory, но нам удалось без проблем использовать функцию "gst_parse_launch()" в IOS и Linux.
Итак, в заключение, пока мы не проверили и не установили приемник UDP, затем попробуйте использовать TCP- метод с использованием элемента tcpclientsrc, включите его, а затем, только когда он заработает, попробуйте найти путь к udp и pls, дайте нам знать, если Вы подходите к концу.
С наилучшими пожеланиями, надеюсь, это поможет многим из вас.
Romain S