decklinksink: Better handling of audio output

Conflicts:

	sys/decklink/gstdecklinksink.cpp
This commit is contained in:
David Schleef 2012-07-02 17:55:37 -07:00 committed by Sebastian Dröge
parent 2a51113351
commit 71dcbbd52a
2 changed files with 66 additions and 26 deletions

View file

@ -299,6 +299,7 @@ gst_decklink_sink_init (GstDecklinkSink * decklinksink,
decklinksink->cond = g_cond_new (); decklinksink->cond = g_cond_new ();
decklinksink->mutex = g_mutex_new (); decklinksink->mutex = g_mutex_new ();
decklinksink->audio_mutex = g_mutex_new (); decklinksink->audio_mutex = g_mutex_new ();
decklinksink->audio_cond = g_cond_new ();
decklinksink->mode = GST_DECKLINK_MODE_NTSC; decklinksink->mode = GST_DECKLINK_MODE_NTSC;
decklinksink->device = 0; decklinksink->device = 0;
@ -430,6 +431,7 @@ gst_decklink_sink_finalize (GObject * object)
/* clean up object here */ /* clean up object here */
g_cond_free (decklinksink->cond); g_cond_free (decklinksink->cond);
g_mutex_free (decklinksink->mutex); g_mutex_free (decklinksink->mutex);
g_cond_free (decklinksink->audio_cond);
g_mutex_free (decklinksink->audio_mutex); g_mutex_free (decklinksink->audio_mutex);
delete decklinksink->callback; delete decklinksink->callback;
@ -462,14 +464,15 @@ gst_decklink_sink_start (GstDecklinkSink * decklinksink)
BMDAudioSampleType sample_depth; BMDAudioSampleType sample_depth;
decklinksink->decklink = gst_decklink_get_nth_device (decklinksink->device); decklinksink->decklink = gst_decklink_get_nth_device (decklinksink->device);
if (decklinksink->decklink) { if (!decklinksink->decklink) {
GST_WARNING ("failed to get device %d", decklinksink->device);
return FALSE; return FALSE;
} }
ret = decklinksink->decklink->QueryInterface (IID_IDeckLinkOutput, ret = decklinksink->decklink->QueryInterface (IID_IDeckLinkOutput,
(void **) &decklinksink->output); (void **) &decklinksink->output);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("selected device does not have output interface"); GST_WARNING ("selected device does not have output interface");
return FALSE; return FALSE;
} }
@ -480,7 +483,7 @@ gst_decklink_sink_start (GstDecklinkSink * decklinksink)
ret = decklinksink->output->EnableVideoOutput (mode->mode, ret = decklinksink->output->EnableVideoOutput (mode->mode,
bmdVideoOutputFlagDefault); bmdVideoOutputFlagDefault);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("failed to enable video output"); GST_WARNING ("failed to enable video output");
return FALSE; return FALSE;
} }
//decklinksink->video_enabled = TRUE; //decklinksink->video_enabled = TRUE;
@ -492,10 +495,10 @@ gst_decklink_sink_start (GstDecklinkSink * decklinksink)
ret = decklinksink->output->EnableAudioOutput (bmdAudioSampleRate48kHz, ret = decklinksink->output->EnableAudioOutput (bmdAudioSampleRate48kHz,
sample_depth, 2, bmdAudioOutputStreamContinuous); sample_depth, 2, bmdAudioOutputStreamContinuous);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("failed to enable audio output"); GST_WARNING ("failed to enable audio output");
return FALSE; return FALSE;
} }
decklinksink->audio_buffer = gst_buffer_new (); decklinksink->audio_adapter = gst_adapter_new ();
decklinksink->num_frames = 0; decklinksink->num_frames = 0;
@ -510,6 +513,10 @@ gst_decklink_sink_force_stop (GstDecklinkSink * decklinksink)
g_cond_signal (decklinksink->cond); g_cond_signal (decklinksink->cond);
g_mutex_unlock (decklinksink->mutex); g_mutex_unlock (decklinksink->mutex);
g_mutex_lock (decklinksink->audio_mutex);
g_cond_signal (decklinksink->audio_cond);
g_mutex_unlock (decklinksink->audio_mutex);
return TRUE; return TRUE;
} }
@ -748,7 +755,7 @@ gst_decklink_sink_videosink_chain (GstPad * pad, GstBuffer * buffer)
ret = decklinksink->output->EnableVideoOutput (decklinksink->display_mode, ret = decklinksink->output->EnableVideoOutput (decklinksink->display_mode,
bmdVideoOutputFlagDefault); bmdVideoOutputFlagDefault);
if (ret != S_OK) { if (ret != S_OK) {
GST_ERROR ("failed to enable video output"); GST_WARNING ("failed to enable video output");
//return FALSE; //return FALSE;
} }
decklinksink->video_enabled = TRUE; decklinksink->video_enabled = TRUE;
@ -820,6 +827,18 @@ gst_decklink_sink_videosink_event (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (decklinksink, "event"); GST_DEBUG_OBJECT (decklinksink, "event");
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
decklinksink->video_eos = TRUE;
decklinksink->video_seqnum = gst_event_get_seqnum (event);
{
GstMessage *message;
message = gst_message_new_eos (GST_OBJECT_CAST (decklinksink));
gst_message_set_seqnum (message, decklinksink->video_seqnum);
gst_element_post_message (GST_ELEMENT_CAST (decklinksink), message);
}
break;
default: default:
res = gst_pad_event_default (pad, event); res = gst_pad_event_default (pad, event);
break; break;
@ -1001,13 +1020,17 @@ gst_decklink_sink_audiosink_chain (GstPad * pad, GstBuffer * buffer)
GST_DEBUG_OBJECT (decklinksink, "chain"); GST_DEBUG_OBJECT (decklinksink, "chain");
// concatenate both buffers if (decklinksink->stop) {
g_mutex_lock (decklinksink->audio_mutex); return GST_FLOW_WRONG_STATE;
decklinksink->audio_buffer = }
gst_buffer_append (decklinksink->audio_buffer, buffer);
g_mutex_unlock (decklinksink->audio_mutex);
// GST_DEBUG("Audio Buffer Size: %d", GST_BUFFER_SIZE (decklinksink->audio_buffer)); g_mutex_lock (decklinksink->audio_mutex);
while (!decklinksink->stop &&
gst_adapter_available (decklinksink->audio_adapter) > 1600 * 4 * 2) {
g_cond_wait (decklinksink->audio_cond, decklinksink->audio_mutex);
}
gst_adapter_push (decklinksink->audio_adapter, buffer);
g_mutex_unlock (decklinksink->audio_mutex);
gst_object_unref (decklinksink); gst_object_unref (decklinksink);
@ -1040,6 +1063,10 @@ gst_decklink_sink_audiosink_event (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (decklinksink, "event"); GST_DEBUG_OBJECT (decklinksink, "event");
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
decklinksink->audio_eos = TRUE;
decklinksink->audio_seqnum = gst_event_get_seqnum (event);
break;
default: default:
res = gst_pad_event_default (pad, event); res = gst_pad_event_default (pad, event);
break; break;
@ -1122,7 +1149,7 @@ HRESULT
HRESULT HRESULT
Output::ScheduledPlaybackHasStopped () Output::ScheduledPlaybackHasStopped ()
{ {
GST_ERROR ("ScheduledPlaybackHasStopped"); GST_DEBUG ("ScheduledPlaybackHasStopped");
return S_OK; return S_OK;
} }
@ -1130,7 +1157,6 @@ HRESULT
Output::RenderAudioSamples (bool preroll) Output::RenderAudioSamples (bool preroll)
{ {
uint32_t samplesWritten; uint32_t samplesWritten;
GstBuffer *buffer;
// guint64 samplesToWrite; // guint64 samplesToWrite;
@ -1139,22 +1165,31 @@ Output::RenderAudioSamples (bool preroll)
decklinksink->output->BeginAudioPreroll (); decklinksink->output->BeginAudioPreroll ();
// running = true; // running = true;
} else { } else {
int n;
const guint8 *data;
g_mutex_lock (decklinksink->audio_mutex); g_mutex_lock (decklinksink->audio_mutex);
decklinksink->output->ScheduleAudioSamples (GST_BUFFER_DATA (decklinksink->audio_buffer), GST_BUFFER_SIZE (decklinksink->audio_buffer) / 4, // 2 bytes per sample, stereo
0, 0, &samplesWritten);
buffer = n = gst_adapter_available (decklinksink->audio_adapter);
gst_buffer_new_and_alloc (GST_BUFFER_SIZE (decklinksink->audio_buffer) - if (n > 0) {
(samplesWritten * 4)); data = gst_adapter_peek (decklinksink->audio_adapter, n);
memcpy (GST_BUFFER_DATA (buffer), decklinksink->output->ScheduleAudioSamples ((void *) data, n / 4,
GST_BUFFER_DATA (decklinksink->audio_buffer) + (samplesWritten * 4), 0, 0, &samplesWritten);
GST_BUFFER_SIZE (decklinksink->audio_buffer) - (samplesWritten * 4));
gst_buffer_unref (decklinksink->audio_buffer); gst_adapter_flush (decklinksink->audio_adapter, samplesWritten * 4);
GST_DEBUG ("wrote %d samples, %d available", samplesWritten, n / 4);
decklinksink->audio_buffer = buffer; g_cond_signal (decklinksink->audio_cond);
} else {
if (decklinksink->audio_eos) {
GstMessage *message;
message = gst_message_new_eos (GST_OBJECT_CAST (decklinksink));
gst_message_set_seqnum (message, decklinksink->audio_seqnum);
gst_element_post_message (GST_ELEMENT_CAST (decklinksink), message);
}
}
g_mutex_unlock (decklinksink->audio_mutex); g_mutex_unlock (decklinksink->audio_mutex);
} }

View file

@ -21,6 +21,7 @@
#define _GST_DECKLINK_SINK_H_ #define _GST_DECKLINK_SINK_H_
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "gstdecklink.h" #include "gstdecklink.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -51,7 +52,7 @@ public IDeckLinkAudioOutputCallback
struct _GstDecklinkSink struct _GstDecklinkSink
{ {
GstElement base_decklinksink; GstElement base_decklinksink;
GstBuffer *audio_buffer; GstAdapter *audio_adapter;
GstPad *videosinkpad; GstPad *videosinkpad;
GstPad *audiosinkpad; GstPad *audiosinkpad;
@ -59,9 +60,13 @@ struct _GstDecklinkSink
GMutex *mutex; GMutex *mutex;
GCond *cond; GCond *cond;
GMutex *audio_mutex; GMutex *audio_mutex;
// GCond *audio_cond; GCond *audio_cond;
int queued_frames; int queued_frames;
gboolean stop; gboolean stop;
gboolean video_eos;
gboolean audio_eos;
int video_seqnum;
int audio_seqnum;
IDeckLink *decklink; IDeckLink *decklink;
IDeckLinkOutput *output; IDeckLinkOutput *output;