То же аудио в gstreamer два результата
Я обнаружил, что если я дважды посылаю одно и то же аудио OGG/Vorbis в конвейер gstreamer 1.0 в программе, я получаю разные аудио (похожие, но не идентичные). Я пытался ссылаться на конвейер и перестраивать его между использованиями, но тоже безрезультатно. Кажется, что-то поддерживает какое-то состояние. Вторая версия такая же, как и другие вторые версии, с такими же отличиями от первой.
Я ищу воспроизводимые результаты от сервера, обрабатывающего аудио, и это мешает.
Извините, это так долго. Похоже, что заставить его воспроизвести и перестроить в конвейер было уместно. Я воспроизвел это с несколькими файлами OGG/vorbis (хотя и не пустыми). Вызовите файл "a.ogg", а затем запустив программу, вы получите "job1.raw" и "job2.raw", которые каждый раз были разными.
Спасибо за любую помощь,
Ричард.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <glib.h>
#include <gst/gst.h>
typedef struct _Decoder2Data {
GstElement * appsrc;
GstElement * decodebin;
GstElement * audioconvert;
GstElement * audioresample;
GstElement * queue1;
GstElement * filesink;
GstElement * pipeline;
GstBus *bus;
const char* request_id;
const char* outdir;
GMainLoop * main_loop;
} Decoder2Data;
void start_request(const char* caps_str, Decoder2Data * data);
void process_data(Decoder2Data * obj, char * audio, int audioSize);
void end_request(Decoder2Data* data);
void finish_request(Decoder2Data * data);
int create_pipeline(int argc, char *argv[], Decoder2Data * data);
void closeGstreamer(Decoder2Data * data);
void *g_loop_thread(void *ptr);
void start_request(const char* caps_str, Decoder2Data * data) {
g_printerr("Test %s: Starting request\n", data->request_id);
g_object_set(data->appsrc, "caps", NULL, NULL);
if (data->outdir) {
char path[128];
sprintf(path, "%s/%s.raw", data->outdir, data->request_id);
FILE *fp = fopen(path, "w+");
if(fp != NULL) {
fclose(fp);
gst_element_set_state(data->pipeline, GST_STATE_PAUSED);
gst_element_set_state(data->filesink, GST_STATE_NULL);
g_object_set(data->filesink, "location", path, NULL);
gst_element_set_state(data->filesink, GST_STATE_PLAYING);
} else {
g_warning("Test %s: Unable to open raw audio file %s.\n", data->request_id, path);
}
}
gst_element_set_state(data->pipeline, GST_STATE_PLAYING);
gst_element_set_state(data->filesink, GST_STATE_PLAYING);
g_printerr("Test Started request\n");
}
void process_data(Decoder2Data * obj, char * audio, int audioSize) {
GstFlowReturn ret;
GstBuffer * buf = gst_buffer_new_and_alloc(audioSize);
gst_buffer_fill(buf, 0, audio, audioSize);
g_signal_emit_by_name (obj->appsrc, "push-buffer", buf, &ret);
if(ret != GST_FLOW_OK)
g_warning("Test Pushing audio resulted in flow state %d\n", ret);
}
void end_request(Decoder2Data* data) {
GstFlowReturn ret;
g_signal_emit_by_name (data->appsrc, "end-of-stream", &ret);
}
GstElement * createElement(const char* name, const char* factoryName) {
GstElement * ret = gst_element_factory_make(name, factoryName);
if (!ret)
g_printerr ("Test failed to create element of type '%s'\n", name);
return ret;
}
// Handler for the pad-added signal
static void _connect_decoder(GstElement *src, GstPad *pad, Decoder2Data *data) {
g_debug("Test _connect_decoder\n");
GstPad * sink_pad = gst_element_get_static_pad (data->audioconvert, "sink");
GstPadLinkReturn ret = gst_pad_link(pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret))
g_printerr("Test Link failed with GstPadLinkError %d.\n", ret);
else
g_debug("Test Link succeeded.\n");
g_debug("Test Connected audio decoder\n");
}
void gstLink(GstElement * src, GstElement * target) {
if (!gst_element_link (src, target))
g_printerr ("Test ----------------- elements could not be linked.\n");
}
static void _on_eos(GstElement *src, GstPad *pad, Decoder2Data *data) {
g_debug("Test _on_eos\n");
finish_request(data);
}
static void _on_error(GstElement *src, GstMessage *pad, Decoder2Data *data) {
g_debug("Test _on_error\n");
GError *err = NULL;
gchar *dbg_info = NULL;
gst_message_parse_error (pad, &err, &dbg_info);
if (err) {
size_t len = strlen(err->message);
g_printerr("ERROR: %s", err->message);
}
g_error_free(err);
g_free(dbg_info);
finish_request(data);
}
void create_and_link(Decoder2Data * data) {
data->appsrc = createElement("appsrc", "appsrc");
data->decodebin = createElement("decodebin", "decodebin");
data->audioconvert = createElement("audioconvert", "audioconvert");
data->audioresample = createElement("audioresample", "audioresample");
data->queue1 = createElement("capsfilter", "capsfilter");
data->filesink = createElement("filesink", "filesink");
g_object_set (data->appsrc, "is-live", TRUE, NULL);
const gchar *caps_str = "audio/x-raw, channels=1, rate=16000, format=S16LE";
GstCaps * caps = gst_caps_from_string(caps_str);
g_object_set (data->queue1, "caps", caps, NULL);
g_object_set (data->filesink, "location", "/dev/null", NULL);
g_debug("Test Created GStreamer elements");
data->pipeline = gst_pipeline_new("pipeline");
if (!data->pipeline) {
g_printerr ("Test pipe line could not be created.\n");
}
// Add all elements to the pipeline
gst_bin_add_many (GST_BIN (data->pipeline), data->appsrc, data->decodebin, data->audioconvert, data->audioresample, data->queue1, data->filesink, NULL);
gstLink(data->appsrc, data->decodebin);
g_signal_connect(data->decodebin, "pad-added", G_CALLBACK (_connect_decoder), data);
gstLink(data->audioconvert, data->audioresample);
gstLink(data->audioresample, data->queue1);
gstLink(data->queue1, data->filesink);
g_debug("Linked GStreamer elements\n");
// Create bus
data->bus = gst_element_get_bus(data->pipeline);
gst_bus_add_signal_watch(data->bus);
gst_bus_enable_sync_message_emission(data->bus);
gst_pipeline_use_clock((GstPipeline*)data->pipeline, (GstClock*)NULL);
g_signal_connect(data->bus, "message::eos", G_CALLBACK(_on_eos), data);
g_signal_connect(data->bus, "message::error", G_CALLBACK(_on_error), data);
}
void finish_request(Decoder2Data * data) {
g_printerr("Test finish_request %s\n", data->request_id);
if (data->outdir) {
gst_element_set_state(data->filesink, GST_STATE_NULL);
g_object_set(data->filesink, "location", "/dev/null", NULL);
gst_element_set_state(data->filesink, GST_STATE_PLAYING);
}
gst_element_set_state(data->pipeline, GST_STATE_NULL);
// Destroy the old pipeline.
gst_element_set_state(data->appsrc, GST_STATE_NULL);
gst_element_set_state(data->decodebin, GST_STATE_NULL);
gst_element_set_state(data->audioconvert, GST_STATE_NULL);
gst_element_set_state(data->audioresample, GST_STATE_NULL);
gst_element_set_state(data->queue1, GST_STATE_NULL);
gst_element_set_state(data->filesink, GST_STATE_NULL);
gst_object_unref(data->pipeline);
// Build a new pipeline
create_and_link(data);
gst_element_set_state(data->pipeline, GST_STATE_READY);
g_printerr("Rebuilt pipeline.");
g_printerr("Finished request complete.\n");
}
int create_pipeline(int argc, char *argv[], Decoder2Data * data) {
g_printerr("Test create_pipeline\n");
gst_init (&argc, &argv);
data->request_id = "<undefined>";
data->outdir = "./";
create_and_link(data);
g_debug("Setting pipeline to READY\n");
gst_element_set_state(data->pipeline, GST_STATE_READY);
g_debug("Set pipeline to READY\n");
return 0;
}
void closeGstreamer(Decoder2Data * data) {
gst_object_unref (data->bus);
gst_element_set_state (data->pipeline, GST_STATE_NULL);
gst_object_unref (data->pipeline);
}
#include <pthread.h>
void *g_loop_thread(void *ptr) {
g_debug("Test main loop thread started\n");
Decoder2Data * data = (Decoder2Data*) ptr;
data->main_loop = g_main_loop_new(NULL, FALSE);
g_debug("Test main loop created, executing g_main_loop_run\n");
g_main_loop_run(data->main_loop); // This is blocking
g_debug("Test main loop thread ENDED\n");
return NULL;
}
int main(int argc, char *argv[]) {
Decoder2Data data;
memset (&data, 0, sizeof (data));
create_pipeline(argc, argv, &data);
pthread_t thread;
int ret = pthread_create(&thread, NULL, g_loop_thread, &data);
if (ret != 0) {
g_printerr("Test Thread not started");
return -1;
}
usleep(250000); // Wait a bit to make sure the thread started
g_printerr("Test starting test\n");
data.request_id = "job1";
start_request("", &data);
FILE * file = fopen("./a.ogg", "rb");
int size = 86*1024/8/4;
char buffer[size];
int n;
while ((n = fread(buffer, 1, size, file)) > 0) {
g_printerr("read %d of data\n", n);
process_data(&data, buffer, n);
}
fclose(file);
g_printerr("finished reading data\n");
end_request(&data);
usleep(250000);
finish_request(&data);
// Switch to second request and do it again.
data.request_id = "job2";
start_request("", &data);
file = fopen("./a.ogg", "rb");
while ((n = fread(buffer, 1, size, file)) > 0) {
g_printerr("read %d of data\n", n);
process_data(&data, buffer, n);
}
fclose(file);
g_printerr("finished reading data again\n");
end_request(&data);
usleep(250000);
finish_request(&data);
g_printerr("waiting for the gstreamer thread to end...\n");
g_main_loop_quit (data.main_loop);
pthread_join(thread, NULL);
g_printerr("Closing\n");
closeGstreamer(&data);
g_printerr("Exit OK\n");
return 0;
}