mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
gst/matroska/: Add support for muxing/demuxing theora video (#342448; too bad none of the usual linux players can act...
Original commit message from CVS: * gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream), (gst_matroska_demux_push_xiph_codec_priv_data), (gst_matroska_demux_parse_blockgroup_or_simpleblock), (gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps): * gst/matroska/matroska-ids.h: * gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init), (gst_matroska_mux_video_pad_setcaps), (xiph3_streamheader_to_codecdata), (vorbis_streamheader_to_codecdata), (theora_streamheader_to_codecdata), (gst_matroska_mux_audio_pad_setcaps), (gst_matroska_mux_write_data): Add support for muxing/demuxing theora video (#342448; too bad none of the usual linux players can actually play this). Playback in GStreamer will require additional changes to theoradec in -base. Refactor streamheaders <=> CodecPrivateData code a bit; some small cleanups.
This commit is contained in:
parent
3ba744c2aa
commit
4e012bac91
4 changed files with 272 additions and 146 deletions
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,23 @@
|
|||
2006-05-23 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
|
||||
(gst_matroska_demux_push_xiph_codec_priv_data),
|
||||
(gst_matroska_demux_parse_blockgroup_or_simpleblock),
|
||||
(gst_matroska_demux_video_caps), (gst_matroska_demux_audio_caps):
|
||||
* gst/matroska/matroska-ids.h:
|
||||
* gst/matroska/matroska-mux.c: (gst_matroska_mux_base_init),
|
||||
(gst_matroska_mux_video_pad_setcaps),
|
||||
(xiph3_streamheader_to_codecdata),
|
||||
(vorbis_streamheader_to_codecdata),
|
||||
(theora_streamheader_to_codecdata),
|
||||
(gst_matroska_mux_audio_pad_setcaps),
|
||||
(gst_matroska_mux_write_data):
|
||||
Add support for muxing/demuxing theora video (#342448; too bad
|
||||
none of the usual linux players can actually play this). Playback
|
||||
in GStreamer will require additional changes to theoradec in -base.
|
||||
Refactor streamheaders <=> CodecPrivateData code a bit; some small
|
||||
cleanups.
|
||||
|
||||
2006-05-22 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* ext/jpeg/gstjpegdec.c: (hresamplecpy1),
|
||||
|
|
|
@ -853,7 +853,6 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux)
|
|||
caps = gst_matroska_demux_audio_caps (audiocontext,
|
||||
context->codec_id,
|
||||
context->codec_priv, context->codec_priv_size, &codec);
|
||||
audiocontext->first_frame = TRUE;
|
||||
if (codec) {
|
||||
list = gst_tag_list_new ();
|
||||
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
|
||||
|
@ -2024,18 +2023,7 @@ gst_matroska_demux_sync_streams (GstMatroskaDemux * demux)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
gst_matroska_demux_stream_is_first_vorbis_frame (GstMatroskaDemux * demux,
|
||||
GstMatroskaTrackContext * stream)
|
||||
{
|
||||
if (stream->type == GST_MATROSKA_TRACK_TYPE_AUDIO
|
||||
&& ((GstMatroskaTrackAudioContext *) stream)->first_frame == TRUE) {
|
||||
return (strcmp (stream->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS) == 0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_matroska_demux_push_vorbis_codec_priv_data (GstMatroskaDemux * demux,
|
||||
gst_matroska_demux_push_xiph_codec_priv_data (GstMatroskaDemux * demux,
|
||||
GstMatroskaTrackContext * stream)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
|
@ -2044,9 +2032,8 @@ gst_matroska_demux_push_vorbis_codec_priv_data (GstMatroskaDemux * demux,
|
|||
guchar *p;
|
||||
gint i;
|
||||
|
||||
/* start of the stream and vorbis audio, need to send the codec_priv
|
||||
* data as first three packets */
|
||||
((GstMatroskaTrackAudioContext *) stream)->first_frame = FALSE;
|
||||
/* start of the stream and vorbis audio or theora video, need to
|
||||
* send the codec_priv data as first three packets */
|
||||
p = (guchar *) stream->codec_priv;
|
||||
offset = 3;
|
||||
|
||||
|
@ -2292,9 +2279,11 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
|
|||
break;
|
||||
}
|
||||
|
||||
if (gst_matroska_demux_stream_is_first_vorbis_frame (demux, stream)) {
|
||||
if (!gst_matroska_demux_push_vorbis_codec_priv_data (demux, stream))
|
||||
if (stream->send_xiph_headers) {
|
||||
if (!gst_matroska_demux_push_xiph_codec_priv_data (demux, stream)) {
|
||||
got_error = TRUE;
|
||||
}
|
||||
stream->send_xiph_headers = FALSE;
|
||||
}
|
||||
|
||||
if (got_error)
|
||||
|
@ -2962,6 +2951,8 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
|
|||
g_assert (videocontext != NULL);
|
||||
g_assert (codec_name != NULL);
|
||||
|
||||
context->send_xiph_headers = FALSE;
|
||||
|
||||
if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC)) {
|
||||
gst_riff_strf_vids *vids = NULL;
|
||||
|
||||
|
@ -3107,6 +3098,9 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext *
|
|||
caps = gst_caps_new_simple ("video/x-pn-realvideo",
|
||||
"rmversion", G_TYPE_INT, rmversion, NULL);
|
||||
*codec_name = g_strdup_printf ("RealVideo %d.0", rmversion);
|
||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_VIDEO_THEORA)) {
|
||||
caps = gst_caps_new_simple ("video/x-theora", NULL);
|
||||
context->send_xiph_headers = TRUE;
|
||||
} else {
|
||||
GST_WARNING ("Unknown codec '%s', cannot build Caps", codec_id);
|
||||
return NULL;
|
||||
|
@ -3232,11 +3226,14 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
|
|||
audiocontext, const gchar * codec_id, gpointer data, guint size,
|
||||
gchar ** codec_name)
|
||||
{
|
||||
GstMatroskaTrackContext *context = (GstMatroskaTrackContext *) audiocontext;
|
||||
GstCaps *caps = NULL;
|
||||
|
||||
g_assert (audiocontext != NULL);
|
||||
g_assert (codec_name != NULL);
|
||||
|
||||
context->send_xiph_headers = FALSE;
|
||||
|
||||
if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1) ||
|
||||
!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L2) ||
|
||||
!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L3)) {
|
||||
|
@ -3288,6 +3285,7 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext *
|
|||
*codec_name = g_strdup ("DTS audio");
|
||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS)) {
|
||||
caps = gst_caps_new_simple ("audio/x-vorbis", NULL);
|
||||
context->send_xiph_headers = TRUE;
|
||||
/* vorbis decoder does tags */
|
||||
} else if (!strcmp (codec_id, GST_MATROSKA_CODEC_ID_AUDIO_ACM)) {
|
||||
gst_riff_strf_auds *auds = NULL;
|
||||
|
|
|
@ -144,6 +144,7 @@
|
|||
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO2 "V_REAL/RV20"
|
||||
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO3 "V_REAL/RV30"
|
||||
#define GST_MATROSKA_CODEC_ID_VIDEO_REALVIDEO4 "V_REAL/RV40"
|
||||
#define GST_MATROSKA_CODEC_ID_VIDEO_THEORA "V_THEORA"
|
||||
/* TODO: Quicktime */
|
||||
|
||||
#define GST_MATROSKA_CODEC_ID_AUDIO_MPEG1_L1 "A_MPEG/L1"
|
||||
|
@ -247,6 +248,15 @@ typedef struct _GstMatroskaTrackContext {
|
|||
guint64 pos;
|
||||
|
||||
gboolean set_discont; /* TRUE = set DISCONT flag on next buffer */
|
||||
|
||||
/* Special flag for Vorbis and Theora, for which we need to send
|
||||
* codec_priv first before sending any data, and just testing
|
||||
* for time == 0 is not enough to detect that. Used by demuxer */
|
||||
gboolean send_xiph_headers;
|
||||
|
||||
/* Special counter for muxer to skip the first N vorbis/theora headers -
|
||||
* they are put into codec private data, not muxed into the stream */
|
||||
guint xiph_headers_to_skip;
|
||||
} GstMatroskaTrackContext;
|
||||
|
||||
typedef struct _GstMatroskaTrackVideoContext {
|
||||
|
@ -263,11 +273,6 @@ typedef struct _GstMatroskaTrackAudioContext {
|
|||
GstMatroskaTrackContext parent;
|
||||
|
||||
guint samplerate, channels, bitdepth;
|
||||
|
||||
/* Special flag for Vorbis, we need to send codec_priv first before
|
||||
* sending any data, and just testing for time == 0 is not enough
|
||||
* to detect that */
|
||||
gboolean first_frame;
|
||||
} GstMatroskaTrackAudioContext;
|
||||
|
||||
typedef struct _GstMatroskaTrackComplexContext {
|
||||
|
|
|
@ -33,18 +33,11 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
|
||||
#define GST_CAT_DEFAULT matroskamux_debug
|
||||
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_WRITING_APP,
|
||||
ARG_MATROSKA_VERSION
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
|
@ -82,6 +75,7 @@ static GstStaticPadTemplate videosink_templ =
|
|||
COMMON_VIDEO_CAPS "; "
|
||||
"image/jpeg, "
|
||||
COMMON_VIDEO_CAPS "; "
|
||||
"video/x-theora; "
|
||||
"video/x-raw-yuv, "
|
||||
"format = (fourcc) { YUY2, I420 }, " COMMON_VIDEO_CAPS)
|
||||
);
|
||||
|
@ -127,15 +121,8 @@ GST_STATIC_PAD_TEMPLATE ("subtitle_%d",
|
|||
|
||||
static GArray *used_uids;
|
||||
|
||||
static void
|
||||
_do_init (GType matroskamux_type)
|
||||
{
|
||||
GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
|
||||
"Matroska muxer");
|
||||
}
|
||||
|
||||
GST_BOILERPLATE_FULL (GstMatroskaMux, gst_matroska_mux, GstElement,
|
||||
GST_TYPE_ELEMENT, _do_init);
|
||||
GST_BOILERPLATE (GstMatroskaMux, gst_matroska_mux, GstElement,
|
||||
GST_TYPE_ELEMENT);
|
||||
|
||||
/* Matroska muxer destructor */
|
||||
static void gst_matroska_mux_finalize (GObject * object);
|
||||
|
@ -166,7 +153,10 @@ static void gst_matroska_mux_reset (GstElement * element);
|
|||
/* uid generation */
|
||||
static guint32 gst_matroska_mux_create_uid ();
|
||||
|
||||
/*static guint gst_matroska_mux_signals[LAST_SIGNAL] = { 0 };*/
|
||||
static gboolean theora_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context);
|
||||
static gboolean vorbis_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context);
|
||||
|
||||
static void
|
||||
gst_matroska_mux_base_init (gpointer g_class)
|
||||
|
@ -187,6 +177,9 @@ gst_matroska_mux_base_init (gpointer g_class)
|
|||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_templ));
|
||||
gst_element_class_set_details (element_class, &gst_matroska_mux_details);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (matroskamux_debug, "matroskamux", 0,
|
||||
"Matroska muxer");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -427,12 +420,15 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
{
|
||||
GstMatroskaTrackContext *context = NULL;
|
||||
GstMatroskaTrackVideoContext *videocontext;
|
||||
GstMatroskaMux *mux;
|
||||
GstMatroskaPad *collect_pad;
|
||||
const gchar *mimetype;
|
||||
gint width, height, pixel_width, pixel_height;
|
||||
const GValue *framerate;
|
||||
GstStructure *structure;
|
||||
|
||||
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
|
||||
|
||||
/* find context */
|
||||
collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
|
||||
g_assert (collect_pad);
|
||||
|
@ -446,6 +442,11 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
|
||||
mimetype = gst_structure_get_name (structure);
|
||||
|
||||
if (!strcmp (mimetype, "video/x-theora")) {
|
||||
/* we'll extract the details later from the theora identification header */
|
||||
goto skip_details;
|
||||
}
|
||||
|
||||
/* get general properties */
|
||||
gst_structure_get_int (structure, "width", &width);
|
||||
gst_structure_get_int (structure, "height", &height);
|
||||
|
@ -476,6 +477,8 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
videocontext->display_height = 0;
|
||||
}
|
||||
|
||||
skip_details:
|
||||
|
||||
videocontext->asr_mode = GST_MATROSKA_ASPECT_RATIO_MODE_FREE;
|
||||
videocontext->eye_mode = GST_MATROSKA_EYE_MODE_MONO;
|
||||
videocontext->fourcc = 0;
|
||||
|
@ -581,6 +584,24 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
context->codec_priv_size = priv_data_size;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
} else if (!strcmp (mimetype, "video/x-theora")) {
|
||||
const GValue *streamheader;
|
||||
|
||||
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_THEORA);
|
||||
|
||||
if (context->codec_priv != NULL) {
|
||||
g_free (context->codec_priv);
|
||||
context->codec_priv = NULL;
|
||||
context->codec_priv_size = 0;
|
||||
}
|
||||
|
||||
streamheader = gst_structure_get_value (structure, "streamheader");
|
||||
if (!theora_streamheader_to_codecdata (streamheader, context)) {
|
||||
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
|
||||
("theora stream headers missing or malformed"));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
} else if (!strcmp (mimetype, "video/mpeg")) {
|
||||
gint mpegversion;
|
||||
|
@ -610,6 +631,182 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xiph3_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context, GstBuffer ** p_buf0)
|
||||
{
|
||||
GstBuffer *buf[3];
|
||||
GArray *bufarr;
|
||||
guint8 *priv_data;
|
||||
guint i, offset, priv_data_size;
|
||||
|
||||
if (streamheader == NULL)
|
||||
goto no_stream_headers;
|
||||
|
||||
if (G_VALUE_TYPE (streamheader) != GST_TYPE_ARRAY)
|
||||
goto wrong_type;
|
||||
|
||||
bufarr = g_value_peek_pointer (streamheader);
|
||||
if (bufarr->len != 3)
|
||||
goto wrong_count;
|
||||
|
||||
context->xiph_headers_to_skip = bufarr->len;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
GValue *bufval = &g_array_index (bufarr, GValue, i);
|
||||
|
||||
if (G_VALUE_TYPE (bufval) != GST_TYPE_BUFFER)
|
||||
goto wrong_content_type;
|
||||
|
||||
buf[i] = g_value_peek_pointer (bufval);
|
||||
}
|
||||
|
||||
priv_data_size = 1;
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[0]) / 0xff + 1;
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[1]) / 0xff + 1;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[i]);
|
||||
}
|
||||
|
||||
priv_data = g_malloc0 (priv_data_size);
|
||||
|
||||
priv_data[0] = 2;
|
||||
offset = 1;
|
||||
|
||||
for (i = 0; i < GST_BUFFER_SIZE (buf[0]) / 0xff; ++i) {
|
||||
priv_data[offset++] = 0xff;
|
||||
}
|
||||
priv_data[offset++] = GST_BUFFER_SIZE (buf[0]) % 0xff;
|
||||
|
||||
for (i = 0; i < GST_BUFFER_SIZE (buf[1]) / 0xff; ++i) {
|
||||
priv_data[offset++] = 0xff;
|
||||
}
|
||||
priv_data[offset++] = GST_BUFFER_SIZE (buf[1]) % 0xff;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
|
||||
GST_BUFFER_SIZE (buf[i]));
|
||||
offset += GST_BUFFER_SIZE (buf[i]);
|
||||
}
|
||||
|
||||
context->codec_priv = priv_data;
|
||||
context->codec_priv_size = priv_data_size;
|
||||
|
||||
if (p_buf0)
|
||||
*p_buf0 = gst_buffer_ref (buf[0]);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
no_stream_headers:
|
||||
{
|
||||
GST_WARNING ("required streamheaders missing in sink caps!");
|
||||
return FALSE;
|
||||
}
|
||||
wrong_type:
|
||||
{
|
||||
GST_WARNING ("streamheaders are not a GST_TYPE_ARRAY, but a %s",
|
||||
G_VALUE_TYPE_NAME (streamheader));
|
||||
return FALSE;
|
||||
}
|
||||
wrong_count:
|
||||
{
|
||||
GST_WARNING ("got %u streamheaders, not 3 as expected", bufarr->len);
|
||||
return FALSE;
|
||||
}
|
||||
wrong_content_type:
|
||||
{
|
||||
GST_WARNING ("streamheaders array does not contain GstBuffers");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vorbis_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context)
|
||||
{
|
||||
GstBuffer *buf0 = NULL;
|
||||
|
||||
if (!xiph3_streamheader_to_codecdata (streamheader, context, &buf0))
|
||||
return FALSE;
|
||||
|
||||
if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 4) {
|
||||
GST_WARNING ("First vorbis header too small, ignoring");
|
||||
} else {
|
||||
if (memcmp (GST_BUFFER_DATA (buf0) + 1, "vorbis", 6) == 0) {
|
||||
GstMatroskaTrackAudioContext *audiocontext;
|
||||
guint8 *hdr;
|
||||
|
||||
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 4;
|
||||
audiocontext = (GstMatroskaTrackAudioContext *) context;
|
||||
audiocontext->channels = GST_READ_UINT8 (hdr);
|
||||
audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (buf0)
|
||||
gst_buffer_unref (buf0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
theora_streamheader_to_codecdata (const GValue * streamheader,
|
||||
GstMatroskaTrackContext * context)
|
||||
{
|
||||
GstBuffer *buf0 = NULL;
|
||||
|
||||
if (!xiph3_streamheader_to_codecdata (streamheader, context, &buf0))
|
||||
return FALSE;
|
||||
|
||||
if (buf0 == NULL || GST_BUFFER_SIZE (buf0) < 1 + 6 + 26) {
|
||||
GST_WARNING ("First theora header too small, ignoring");
|
||||
} else if (memcmp (GST_BUFFER_DATA (buf0), "\200theora\003\002", 9) != 0) {
|
||||
GST_WARNING ("First header not a theora identification header, ignoring");
|
||||
} else {
|
||||
GstMatroskaTrackVideoContext *videocontext;
|
||||
guint fps_num, fps_denom, par_num, par_denom;
|
||||
guint8 *hdr;
|
||||
|
||||
hdr = GST_BUFFER_DATA (buf0) + 1 + 6 + 3 + 2 + 2;
|
||||
|
||||
videocontext = (GstMatroskaTrackVideoContext *) context;
|
||||
videocontext->pixel_width = GST_READ_UINT32_BE (hdr) >> 8;
|
||||
videocontext->pixel_height = GST_READ_UINT32_BE (hdr + 3) >> 8;
|
||||
hdr += 3 + 3 + 1 + 1;
|
||||
fps_num = GST_READ_UINT32_BE (hdr);
|
||||
fps_denom = GST_READ_UINT32_BE (hdr + 4);
|
||||
context->default_duration = gst_util_uint64_scale_int (GST_SECOND,
|
||||
fps_denom, fps_num);
|
||||
hdr += 4 + 4;
|
||||
par_num = GST_READ_UINT32_BE (hdr) >> 8;
|
||||
par_denom = GST_READ_UINT32_BE (hdr + 3) >> 8;
|
||||
if (par_num > 0 && par_num > 0) {
|
||||
if (par_num > par_denom) {
|
||||
videocontext->display_width =
|
||||
videocontext->pixel_width * par_num / par_denom;
|
||||
videocontext->display_height = videocontext->pixel_height;
|
||||
} else if (par_num < par_denom) {
|
||||
videocontext->display_width = videocontext->pixel_width;
|
||||
videocontext->display_height =
|
||||
videocontext->pixel_height * par_denom / par_num;
|
||||
} else {
|
||||
videocontext->display_width = 0;
|
||||
videocontext->display_height = 0;
|
||||
}
|
||||
} else {
|
||||
videocontext->display_width = 0;
|
||||
videocontext->display_height = 0;
|
||||
}
|
||||
hdr += 3 + 3;
|
||||
}
|
||||
|
||||
if (buf0)
|
||||
gst_buffer_unref (buf0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_matroska_mux_audio_pad_setcaps:
|
||||
|
@ -625,11 +822,14 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
{
|
||||
GstMatroskaTrackContext *context = NULL;
|
||||
GstMatroskaTrackAudioContext *audiocontext;
|
||||
GstMatroskaMux *mux;
|
||||
GstMatroskaPad *collect_pad;
|
||||
const gchar *mimetype;
|
||||
gint samplerate = 0, channels = 0;
|
||||
GstStructure *structure;
|
||||
|
||||
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
|
||||
|
||||
/* find context */
|
||||
collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
|
||||
g_assert (collect_pad);
|
||||
|
@ -716,8 +916,6 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
/* FIXME: endianness is undefined */
|
||||
} else if (!strcmp (mimetype, "audio/x-vorbis")) {
|
||||
const GValue *streamheader;
|
||||
guint8 *priv_data = NULL;
|
||||
guint priv_data_size = 0;
|
||||
|
||||
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_VORBIS);
|
||||
|
||||
|
@ -726,81 +924,14 @@ gst_matroska_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps)
|
|||
context->codec_priv = NULL;
|
||||
context->codec_priv_size = 0;
|
||||
}
|
||||
|
||||
streamheader = gst_structure_get_value (structure, "streamheader");
|
||||
|
||||
if (streamheader != NULL) {
|
||||
if (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) {
|
||||
GArray *bufarr = g_value_peek_pointer (streamheader);
|
||||
gint i;
|
||||
gint offset;
|
||||
|
||||
if (bufarr->len == 3) {
|
||||
GstBuffer *buf[3];
|
||||
|
||||
for (i = 0; i < bufarr->len; i++) {
|
||||
GValue *bufval = &g_array_index (bufarr, GValue, i);
|
||||
|
||||
if (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER) {
|
||||
buf[i] = g_value_peek_pointer (bufval);
|
||||
}
|
||||
}
|
||||
|
||||
priv_data_size = 1;
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[0]) / 0xff + 1;
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[1]) / 0xff + 1;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
priv_data_size += GST_BUFFER_SIZE (buf[i]);
|
||||
}
|
||||
|
||||
priv_data = g_malloc0 (priv_data_size);
|
||||
|
||||
priv_data[0] = 2;
|
||||
offset = 1;
|
||||
|
||||
for (i = 0; i < GST_BUFFER_SIZE (buf[0]) / 0xff; ++i) {
|
||||
priv_data[offset++] = 0xff;
|
||||
}
|
||||
priv_data[offset++] = GST_BUFFER_SIZE (buf[0]) % 0xff;
|
||||
|
||||
for (i = 0; i < GST_BUFFER_SIZE (buf[1]) / 0xff; ++i) {
|
||||
priv_data[offset++] = 0xff;
|
||||
}
|
||||
priv_data[offset++] = GST_BUFFER_SIZE (buf[1]) % 0xff;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
memcpy (priv_data + offset, GST_BUFFER_DATA (buf[i]),
|
||||
GST_BUFFER_SIZE (buf[i]));
|
||||
offset += GST_BUFFER_SIZE (buf[i]);
|
||||
}
|
||||
|
||||
if (GST_BUFFER_SIZE (buf[0]) < 1 + 6 + 4) {
|
||||
GST_WARNING ("First vorbis header too small, ignoring");
|
||||
} else {
|
||||
if (memcmp (GST_BUFFER_DATA (buf[0]) + 1, "vorbis", 6) == 0) {
|
||||
guint8 *hdr = GST_BUFFER_DATA (buf[0]) + 1 + 6 + 4;
|
||||
|
||||
audiocontext->channels = GST_READ_UINT8 (hdr);
|
||||
audiocontext->samplerate = GST_READ_UINT32_LE (hdr + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_WARNING ("Vorbis header does not contain "
|
||||
"three buffers (found %d buffers), Ignoring.", bufarr->len);
|
||||
}
|
||||
}
|
||||
if (!vorbis_streamheader_to_codecdata (streamheader, context)) {
|
||||
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
|
||||
("vorbis stream headers missing or malformed"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv_data == NULL) {
|
||||
GST_WARNING ("Could not write Vorbis header into codec private data. "
|
||||
"You will probably not be able to play the stream.");
|
||||
}
|
||||
|
||||
context->codec_priv_size = priv_data_size;
|
||||
context->codec_priv = (gpointer) priv_data;
|
||||
|
||||
return TRUE;
|
||||
|
||||
} else if (!strcmp (mimetype, "audio/x-ac3")) {
|
||||
context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_AC3);
|
||||
|
||||
|
@ -1304,35 +1435,6 @@ gst_matroska_mux_best_pad (GstMatroskaMux * mux, gboolean * popped)
|
|||
return best;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_matroska_mux_stream_is_vorbis_header (GstMatroskaMux * mux,
|
||||
GstMatroskaPad * collect_pad)
|
||||
{
|
||||
GstMatroskaTrackAudioContext *audio_ctx;
|
||||
|
||||
audio_ctx = (GstMatroskaTrackAudioContext *) collect_pad->track;
|
||||
|
||||
if (collect_pad->track->type != GST_MATROSKA_TRACK_TYPE_AUDIO)
|
||||
return FALSE;
|
||||
|
||||
if (audio_ctx->first_frame != FALSE)
|
||||
return FALSE;
|
||||
|
||||
if (collect_pad->track->codec_id == NULL ||
|
||||
strcmp (collect_pad->track->codec_id, GST_MATROSKA_CODEC_ID_AUDIO_VORBIS))
|
||||
return FALSE;
|
||||
|
||||
/* HACK: three frame headers are counted using pos */
|
||||
if (++collect_pad->track->pos <= 3)
|
||||
return TRUE;
|
||||
|
||||
/* 4th vorbis packet => skipped all headers */
|
||||
collect_pad->track->pos = 0;
|
||||
audio_ctx->first_frame = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gst_matroska_mux_buffer_header:
|
||||
* @track: Track context.
|
||||
|
@ -1386,10 +1488,11 @@ gst_matroska_mux_write_data (GstMatroskaMux * mux, GstMatroskaPad * collect_pad)
|
|||
buf = collect_pad->buffer;
|
||||
collect_pad->buffer = NULL;
|
||||
|
||||
/* vorbis header are retrieved from caps and placed in CodecPrivate */
|
||||
if (gst_matroska_mux_stream_is_vorbis_header (mux, collect_pad)) {
|
||||
GST_LOG_OBJECT (collect_pad->collect.pad, "dropping vorbis header buffer");
|
||||
/* vorbis/theora headers are retrieved from caps and put in CodecPrivate */
|
||||
if (collect_pad->track->xiph_headers_to_skip > 0) {
|
||||
GST_LOG_OBJECT (collect_pad->collect.pad, "dropping streamheader buffer");
|
||||
gst_buffer_unref (buf);
|
||||
--collect_pad->track->xiph_headers_to_skip;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue