То же аудио в 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;
}

0 ответов

Другие вопросы по тегам