#video #audio #gstreamer
#Видео #Аудио #gstreamer
Вопрос:
Как я могу воспроизводить аудио и видео вместе в приложении GStreamer, кроме playbin / playbin2?
как я могу после демультиплексирования воспроизводить аудио в аудиопотоке и видео в видеопотоке?
Пожалуйста, ответьте.Если возможно, пожалуйста, приведите один пример кода. Заранее спасибо.
Ответ №1:
Вот пример файла ogg
gst-launch filesrc location=test.ogg ! oggdemux name=demuxer
demuxer. ! queue ! vorbisdec ! audioconvert ! audioresample ! autoaudiosink
demuxer. ! queue ! theoradec ! ffmpegcolorspace ! autovideosink
Комментарии:
1. Большое спасибо. В моем приложении это работает нормально. Не могли бы вы, пожалуйста, сказать мне одну вещь, если у меня есть контейнер mp4 и кодек H.264, то какой плагин я буду использовать?
2. Предполагая, что аудио является AAC, модифицированный конвейер будет выглядеть следующим образом gst-запустите filesrc location=test.mp4 ! qtdemux name=демультипликатор demuxer. ! очередь! faad! аудиоконвертировать! аудиовыборка! автоматическое отключение звука демультиплексирование. ! очередь! x264dec! ffmpegcolorspace! автовидеосиньк
3. Надеюсь, еще не так поздно, не могли бы вы, пожалуйста, сказать мне, как я мог бы это сделать для . веб-видео?
Ответ №2:
У меня это отлично работает с использованием языка C:
//vdoAdoOGGPlayer.c
#include <gst/gst.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Queue {
GstElement *queue[2];
} Queue;
void get_stream_type (char **result, char *file);
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data);
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data);
int main (int argc, char *argv[])
{
GMainLoop *loop;
GstElement *pipeline, *source, *demuxer, *decoder, *conv, *sink;
GstBus *bus;
guint bus_watch_id;
/* Check input arguments */
if (argc != 2) {
g_printerr ("Usage: %s <Ogg/Vorbis filename>n", argv[0]);
return -1;
}
/* Initialisation */
gst_init (amp;argc, amp;argv);
loop = g_main_loop_new (NULL, FALSE);
/* Create gstreamer elements */
pipeline = gst_pipeline_new ("audio-player");
source = gst_element_factory_make ("filesrc", "file-source");
demuxer = gst_element_factory_make ("oggdemux", "ogg-demuxer");
/*视频解析转流输出元素*/
decoder = gst_element_factory_make ("theoradec", "vorbis-decoder");
conv = gst_element_factory_make ("videoconvert", "converter");
sink = gst_element_factory_make ("autovideosink", "video-output");
/*音频解析转流输出元素*/
GstElement *decoder_audio = gst_element_factory_make ("vorbisdec", "audio-decoder");
GstElement *converter_audio = gst_element_factory_make ("audioconvert", "audio_converter");
GstElement *sink_audio = gst_element_factory_make ("autoaudiosink", "audio-ouput");
if (!pipeline || !source || !demuxer || !decoder || !conv || !sink ) {
g_printerr ("One element could not be created. Exiting.n");
return -1;
}
/* Set up the pipeline */
g_object_set (G_OBJECT (source), "location", argv[1], NULL);
GstElement *vdoQueue = NULL;
GstElement *audioQueue = NULL;
char format1[10] = { 0 };
char format2[10] = { 0 };
char *result[2];
result[0] = format1;
result[1] = format2;
/*获取包含的流编码格式*/
get_stream_type(result, argv[1]);
/*如果包含theora编码格式,则含有视频流,进行相关元素的添加和链接*/
if (strcmp (format1, "theora") == 0 || strcmp (format2, "theora") == 0) {
vdoQueue = gst_element_factory_make ("queue", "video-queue");
gst_bin_add_many (GST_BIN(pipeline), vdoQueue, decoder, conv, sink , NULL);
gst_element_link_many (vdoQueue, decoder, conv, sink, NULL);
}
if (strcmp (format1, "vorbis") == 0 || strcmp (format2, "vorbis") == 0) {
audioQueue = gst_element_factory_make ("queue", "audio-queue");
gst_bin_add_many (GST_BIN(pipeline), audioQueue,
decoder_audio, converter_audio, sink_audio, NULL);
gst_element_link_many (audioQueue, decoder_audio,
converter_audio, sink_audio, NULL);
}
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_bin_add_many (GST_BIN (pipeline), source, demuxer,NULL);
if ( gst_element_link (source, demuxer) != TRUE ){
g_print("Elements couldn't be linkedn");
return 1;
}
Queue queue;
queue.queue[0] = audioQueue;
queue.queue[1] = vdoQueue;
g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), (void*)amp;queue);
/* note that the demuxer will be linked to the decoder dynamically.
The reason is that Ogg may contain various streams (for example
audio and video). The source pad(s) will be created at run time,
by the demuxer when it detects the amount and nature of streams.
Therefore we connect a callback function which will be executed
when the "pad-added" is emitted.*/
/* Set the pipeline to "playing" state*/
g_print ("Now playing: %sn", argv[1]);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Iterate */
g_print ("Running...n");
g_main_loop_run (loop);
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playbackn");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Deleting pipelinen");
gst_object_unref (GST_OBJECT (pipeline));
g_source_remove (bus_watch_id);
g_main_loop_unref (loop);
return 0;
}
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sinkpad_audio, *sinkpad_vdo;
Queue *queue = (Queue *) data;
/* We can now link this pad with the vorbis-decoder sink pad */
g_print ("Dynamic pad created, linking demuxer/decodern");
/*queue元素值不为空则进行pad的连接*/
if ( queue->queue[0] ) {
sinkpad_audio = gst_element_get_static_pad (queue->queue[0], "sink");
GstPad *pad1 = gst_element_get_compatible_pad (element, sinkpad_audio, NULL);
if ( pad1 ) {
gst_pad_link(pad1, sinkpad_audio);
gst_object_unref (GST_OBJECT (pad1));
g_print("link audion");
}
gst_object_unref (sinkpad_audio);
}
if ( queue->queue[1] ) {
sinkpad_vdo = gst_element_get_static_pad (queue->queue[1], "sink");
GstPad *pad2 = gst_element_get_compatible_pad (element, sinkpad_vdo, NULL);
if ( pad2 ) {
gst_pad_link(pad2, sinkpad_vdo);
gst_object_unref (GST_OBJECT (pad2));
g_print("link videon");
}
gst_object_unref (sinkpad_vdo);
}
}
void get_stream_type(char **result, char *file) {
char buf[110];
FILE *fp = fopen(file, "r");
if ( !fp ) {
fprintf(stderr, "Open file failedn");
exit(1);
}
if ( fread (buf, sizeof(char), sizeof(buf), fp) < 0) {
fprintf (stderr, "fread failedn");
exit(1);
}
/*extract vorbis or theora format name if it's exist
* and record its index*/
int i1 = 0, i2 = 0;
for ( int i=0; i<110; i ) {
if (buf[i]=='t' || buf[i]=='v') {
if ( !i1 )
i1 = i;
else
i2 = i;
}
}
buf[i1 6] = buf[i2 6] = '';
strcpy(result[0], amp;buf[i1]);
strcpy(result[1], amp;buf[i2]);
result[0][6] = result[1][6] = '';
printf("%sn", result[0]);
printf("%sn", result[1]);
fclose (fp);
}
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End of streamn");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR:
{
gchar *debug;
GError *error;
gst_message_parse_error (msg, amp;error, amp;debug);
g_free (debug);
g_printerr ("Error: %sn", error->message);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
Скомпилируйте с помощью команды:
gcc `pkg-config --cflags --libs gstreamer-1.0` vdoAdoOGGPlayer.c -g -o vdoAdoOGGPlayer
Выполнить:
./vdoAdoOGGPlayer file.ogg
Более подробная информация об этом коде в этой статье:
нажмите на меня