mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-09 08:55:33 +00:00
qtdemux: Add support for FLAC encapsulated in ISOBMFF
As defined by https://git.xiph.org/?p=flac.git;a=blob_plain;f=doc/isoflac.txt https://bugzilla.gnome.org/show_bug.cgi?id=773712
This commit is contained in:
parent
15630db146
commit
2ad30254c3
5 changed files with 167 additions and 0 deletions
|
@ -86,6 +86,8 @@ G_BEGIN_DECLS
|
|||
#define FOURCC_ac_3 GST_MAKE_FOURCC('a','c','-','3')
|
||||
#define FOURCC_agsm GST_MAKE_FOURCC('a','g','s','m')
|
||||
#define FOURCC_alac GST_MAKE_FOURCC('a','l','a','c')
|
||||
#define FOURCC_fLaC GST_MAKE_FOURCC('f','L','a','C')
|
||||
#define FOURCC_dfLa GST_MAKE_FOURCC('d','f','L','a')
|
||||
#define FOURCC_alaw GST_MAKE_FOURCC('a','l','a','w')
|
||||
#define FOURCC_alis GST_MAKE_FOURCC('a','l','i','s')
|
||||
#define FOURCC_appl GST_MAKE_FOURCC('a','p','p','l')
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Copyright (C) <2013> Intel Corporation
|
||||
* Copyright (C) <2014> Centricular Ltd
|
||||
* Copyright (C) <2015> YouView TV Ltd.
|
||||
* Copyright (C) <2016> British Broadcasting Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
|
@ -7076,6 +7077,7 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
|
|||
}
|
||||
case FOURCC_mp4a:
|
||||
case FOURCC_alac:
|
||||
case FOURCC_fLaC:
|
||||
{
|
||||
guint32 version;
|
||||
guint32 offset;
|
||||
|
@ -7085,6 +7087,8 @@ qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
|
|||
* since a similar layout is used in other cases as well */
|
||||
if (fourcc == FOURCC_mp4a)
|
||||
min_size = 20;
|
||||
else if (fourcc == FOURCC_fLaC)
|
||||
min_size = 86;
|
||||
else
|
||||
min_size = 40;
|
||||
|
||||
|
@ -10858,6 +10862,89 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
|
|||
"samplesize", G_TYPE_INT, samplesize, NULL);
|
||||
break;
|
||||
}
|
||||
case FOURCC_fLaC:
|
||||
{
|
||||
/* The codingname of the sample entry is 'fLaC' */
|
||||
GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
|
||||
|
||||
if (flac) {
|
||||
/* The 'dfLa' box is added to the sample entry to convey
|
||||
initializing information for the decoder. */
|
||||
const GNode *dfla =
|
||||
qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
|
||||
|
||||
if (dfla) {
|
||||
const guint32 len = QT_UINT32 (dfla->data);
|
||||
|
||||
/* Must contain at least dfLa box header (12),
|
||||
* METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
|
||||
if (len < 50) {
|
||||
GST_DEBUG_OBJECT (qtdemux,
|
||||
"discarding dfla atom with unexpected len %d", len);
|
||||
} else {
|
||||
/* skip dfLa header to get the METADATA_BLOCKs */
|
||||
const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
|
||||
const guint32 metadata_blocks_len = len - 12;
|
||||
|
||||
gchar *stream_marker = g_strdup ("fLaC");
|
||||
GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
|
||||
strlen (stream_marker));
|
||||
|
||||
guint index = 0;
|
||||
gboolean is_last = FALSE;
|
||||
|
||||
GValue array = G_VALUE_INIT;
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&array, GST_TYPE_ARRAY);
|
||||
g_value_init (&value, GST_TYPE_BUFFER);
|
||||
|
||||
gst_value_set_buffer (&value, block);
|
||||
gst_value_array_append_value (&array, &value);
|
||||
g_value_reset (&value);
|
||||
|
||||
gst_buffer_unref (block);
|
||||
|
||||
while (is_last == FALSE && index < metadata_blocks_len) {
|
||||
/* add the METADATA_BLOCK_HEADER size to the signalled size */
|
||||
const guint block_size = 4 +
|
||||
(metadata_blocks[index + 1] << 16) +
|
||||
(metadata_blocks[index + 2] << 8) +
|
||||
metadata_blocks[index + 3];
|
||||
|
||||
is_last = metadata_blocks[index] >> 7;
|
||||
|
||||
block = gst_buffer_new_and_alloc (block_size);
|
||||
|
||||
gst_buffer_fill (block, 0, &metadata_blocks[index],
|
||||
block_size);
|
||||
|
||||
gst_value_set_buffer (&value, block);
|
||||
gst_value_array_append_value (&array, &value);
|
||||
g_value_reset (&value);
|
||||
|
||||
gst_buffer_unref (block);
|
||||
|
||||
index += block_size;
|
||||
}
|
||||
|
||||
gst_structure_set_value (gst_caps_get_structure (stream->caps,
|
||||
0), "streamheader", &array);
|
||||
|
||||
g_value_unset (&value);
|
||||
g_value_unset (&array);
|
||||
|
||||
/* The sample rate obtained from the stsd may not be accurate
|
||||
* since it cannot represent rates greater than 65535Hz, so
|
||||
* override that value with the sample rate from the
|
||||
* METADATA_BLOCK_STREAMINFO block */
|
||||
stream->rate =
|
||||
(QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FOURCC_sawb:
|
||||
/* Fallthrough! */
|
||||
amrwb = TRUE;
|
||||
|
@ -13615,6 +13702,11 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
|
|||
_codec ("Apple lossless audio");
|
||||
caps = gst_caps_new_empty_simple ("audio/x-alac");
|
||||
break;
|
||||
case FOURCC_fLaC:
|
||||
_codec ("Free Lossless Audio Codec");
|
||||
caps = gst_caps_new_simple ("audio/x-flac",
|
||||
"framed", G_TYPE_BOOLEAN, TRUE, NULL);
|
||||
break;
|
||||
case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
|
||||
_codec ("QualComm PureVoice");
|
||||
caps = gst_caps_from_string ("audio/qcelp");
|
||||
|
|
|
@ -340,6 +340,9 @@ qtdemux_dump_stsd (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
|||
if (!qtdemux_dump_stsd_avc1 (qtdemux, &sub, size, depth + 1))
|
||||
return FALSE;
|
||||
break;
|
||||
case FOURCC_fLaC:
|
||||
/* will be dumped by node_dump_foreach */
|
||||
break;
|
||||
case FOURCC_mp4s:
|
||||
if (!gst_byte_reader_get_uint32_be (&sub, &ver_flags) ||
|
||||
!gst_byte_reader_get_uint32_be (&sub, &num_entries))
|
||||
|
@ -890,6 +893,70 @@ qtdemux_dump_svmi (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
qtdemux_dump_dfLa (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||
{
|
||||
const gchar *block_types[] = {
|
||||
"STREAMINFO", "PADDING", "APPLICATION", "SEEKTABLE", "VORBIS_COMMENT",
|
||||
"CUESHEET", "PICTURE", "UNKNOWN", "INVALID"
|
||||
};
|
||||
|
||||
guint32 ver_flags, block_header, block_size;
|
||||
gint8 block_type;
|
||||
gboolean isLast = FALSE;
|
||||
|
||||
if (!gst_byte_reader_get_uint32_be (data, &ver_flags))
|
||||
return FALSE;
|
||||
|
||||
GST_LOG ("%*s version/flags: %08x", depth, "", ver_flags);
|
||||
|
||||
do {
|
||||
if (!gst_byte_reader_get_uint32_be (data, &block_header))
|
||||
break;
|
||||
|
||||
isLast = (block_header >> 31) & 1;
|
||||
block_type = (block_header >> 24) & 0x7F;
|
||||
block_size = block_header & 0xFFFFFF;
|
||||
|
||||
if (block_type == 127)
|
||||
block_type = 8;
|
||||
else if (block_type > 6)
|
||||
block_type = 7;
|
||||
|
||||
GST_LOG ("%*s block_type: %s", depth, "", block_types[block_type]);
|
||||
GST_LOG ("%*s last-block-flag: %s", depth, "", isLast ? "true" : "false");
|
||||
GST_LOG ("%*s length: %d", depth, "", block_size);
|
||||
|
||||
if (!gst_byte_reader_skip (data, block_size))
|
||||
break;
|
||||
} while (!isLast);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
qtdemux_dump_fLaC (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||
{
|
||||
guint16 data_ref_id, n_channels, sample_size;
|
||||
guint32 sample_rate;
|
||||
|
||||
if (!gst_byte_reader_skip (data, 6) ||
|
||||
!gst_byte_reader_get_uint16_be (data, &data_ref_id) ||
|
||||
!gst_byte_reader_skip (data, 8) ||
|
||||
!gst_byte_reader_get_uint16_be (data, &n_channels) ||
|
||||
!gst_byte_reader_get_uint16_be (data, &sample_size) ||
|
||||
!gst_byte_reader_skip (data, 4) ||
|
||||
!gst_byte_reader_get_uint32_be (data, &sample_rate))
|
||||
return FALSE;
|
||||
|
||||
GST_LOG ("%*s data reference: %d", depth, "", data_ref_id);
|
||||
GST_LOG ("%*s channel count: %d", depth, "", n_channels);
|
||||
GST_LOG ("%*s sample size: %d", depth, "", sample_size);
|
||||
GST_LOG ("%*s sample rate: %d", depth, "", (sample_rate >> 16));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data, int depth)
|
||||
{
|
||||
|
|
|
@ -85,6 +85,10 @@ gboolean qtdemux_dump_unknown (GstQTDemux * qtdemux, GstByteReader * data,
|
|||
int depth);
|
||||
gboolean qtdemux_dump_svmi (GstQTDemux *qtdemux, GstByteReader *data,
|
||||
int depth);
|
||||
gboolean qtdemux_dump_dfLa (GstQTDemux * qtdemux, GstByteReader * data,
|
||||
int depth);
|
||||
gboolean qtdemux_dump_fLaC (GstQTDemux * qtdemux, GstByteReader * data,
|
||||
int depth);
|
||||
|
||||
gboolean qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ static const QtNodeType qt_node_types[] = {
|
|||
{FOURCC_fiel, "fiel", 0,},
|
||||
{FOURCC_jp2x, "jp2x", 0,},
|
||||
{FOURCC_alac, "alac", 0,},
|
||||
{FOURCC_fLaC, "fLaC", 0, qtdemux_dump_fLaC},
|
||||
{FOURCC_dfLa, "dfLa", 0, qtdemux_dump_dfLa},
|
||||
{FOURCC_wave, "wave", QT_FLAG_CONTAINER},
|
||||
{FOURCC_appl, "appl", QT_FLAG_CONTAINER},
|
||||
{FOURCC_esds, "esds", 0},
|
||||
|
|
Loading…
Reference in a new issue