[vlc-commits] demux: mp4: rework audio samples handling
Francois Cartegnie
git at videolan.org
Thu Apr 16 15:50:50 CEST 2020
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Apr 1 15:39:21 2020 +0200| [962ae9594cc757965765070c22604c85ca41f144] | committer: Francois Cartegnie
demux: mp4: rework audio samples handling
hacks no longer needed, refactors parameters
and removes sample description modifications
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=962ae9594cc757965765070c22604c85ca41f144
---
modules/demux/mp4/essetup.c | 79 ------------
modules/demux/mp4/mp4.c | 306 ++++++++++++++++++++++++--------------------
2 files changed, 167 insertions(+), 218 deletions(-)
diff --git a/modules/demux/mp4/essetup.c b/modules/demux/mp4/essetup.c
index 9d3ef27957..c6cc34871e 100644
--- a/modules/demux/mp4/essetup.c
+++ b/modules/demux/mp4/essetup.c
@@ -791,75 +791,6 @@ int SetupAudioES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample )
p_track->fmt.i_original_fourcc = p_sample->i_type;
- if( ( p_track->i_sample_size == 1 || p_track->i_sample_size == 2 ) )
- {
- if( p_soun->i_qt_version == 0 )
- {
- switch( p_sample->i_type )
- {
- case VLC_CODEC_ADPCM_IMA_QT:
- p_soun->i_qt_version = 1;
- p_soun->i_sample_per_packet = 64;
- p_soun->i_bytes_per_packet = 34;
- p_soun->i_bytes_per_frame = 34 * p_soun->i_channelcount;
- p_soun->i_bytes_per_sample = 2;
- break;
- case VLC_CODEC_MACE3:
- p_soun->i_qt_version = 1;
- p_soun->i_sample_per_packet = 6;
- p_soun->i_bytes_per_packet = 2;
- p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount;
- p_soun->i_bytes_per_sample = 2;
- break;
- case VLC_CODEC_MACE6:
- p_soun->i_qt_version = 1;
- p_soun->i_sample_per_packet = 12;
- p_soun->i_bytes_per_packet = 2;
- p_soun->i_bytes_per_frame = 2 * p_soun->i_channelcount;
- p_soun->i_bytes_per_sample = 2;
- break;
- default:
- p_track->fmt.i_codec = p_sample->i_type;
- break;
- }
-
- }
- else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 )
- {
- p_soun->i_qt_version = 0;
- }
- }
- else if( p_sample->data.p_sample_soun->i_qt_version == 1 )
- {
- switch( p_sample->i_type )
- {
- case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
- case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
- {
- if( p_track->i_sample_size > 1 )
- p_soun->i_qt_version = 0;
- break;
- }
- case( ATOM_ac3 ):
- case( ATOM_eac3 ):
- case( VLC_FOURCC( 'm', 's', 0x20, 0x00 ) ):
- p_soun->i_qt_version = 0;
- break;
- default:
- break;
- }
-
- if ( p_sample->data.p_sample_soun->i_compressionid == 0xFFFE /* -2 */)
- {
- /* redefined sample tables for vbr audio */
- }
- else if ( p_track->i_sample_size != 0 && p_soun->i_sample_per_packet == 0 )
- {
- msg_Err( p_demux, "Invalid sample per packet value for qt_version 1. Broken muxer! %u %u",
- p_track->i_sample_size, p_soun->i_sample_per_packet );
- p_soun->i_qt_version = 0;
- }
- }
/* Endianness atom */
const MP4_Box_t *p_enda = MP4_BoxGet( p_sample, "wave/enda" );
@@ -1148,8 +1079,6 @@ int SetupAudioES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample )
p_track->fmt.audio.i_blockalign =
p_soun->i_channelcount * p_soun->i_constbitsperchannel / 8;
p_track->i_sample_size = p_track->fmt.audio.i_blockalign;
-
- p_soun->i_qt_version = 0;
break;
}
}
@@ -1268,14 +1197,6 @@ int SetupAudioES( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_sample )
if (p_SA3D && BOXDATA(p_SA3D))
p_track->fmt.audio.channel_type = AUDIO_CHANNEL_TYPE_AMBISONICS;
- /* Late fixes */
- if ( p_soun->i_qt_version == 0 && p_track->fmt.i_codec == VLC_CODEC_QCELP )
- {
- /* Shouldn't be v0, as it is a compressed codec !*/
- p_soun->i_qt_version = 1;
- p_soun->i_compressionid = 0xFFFE;
- }
-
return 1;
}
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 987ba39218..3b18f734a2 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -2820,16 +2820,15 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
return VLC_EGENERIC;
}
- p_track->p_sample = p_sample;
-
MP4_Box_t *p_frma;
- if( ( p_frma = MP4_BoxGet( p_track->p_sample, "sinf/frma" ) ) && p_frma->data.p_frma )
+ if( ( p_frma = MP4_BoxGet( p_sample, "sinf/frma" ) ) && p_frma->data.p_frma )
{
msg_Warn( p_demux, "Original Format Box: %4.4s", (char *)&p_frma->data.p_frma->i_type );
p_sample->i_type = p_frma->data.p_frma->i_type;
}
+ p_track->p_sample = p_sample;
p_track->fmt.i_id = p_track->i_track_ID;
/* */
@@ -3112,8 +3111,8 @@ static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
/* now see if actual es is ok */
if( p_track->i_chunk >= p_track->i_chunk_count ||
- p_track->chunk[p_track->i_chunk].i_sample_description_index !=
- p_track->chunk[i_chunk].i_sample_description_index )
+ (p_track->chunk[p_track->i_chunk].i_sample_description_index !=
+ p_track->chunk[i_chunk].i_sample_description_index ) )
{
msg_Warn( p_demux, "recreate ES for track[Id 0x%x]",
p_track->i_track_ID );
@@ -3580,26 +3579,38 @@ static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
* 3 types: for audio
*
*/
-static inline uint32_t MP4_GetFixedSampleSize( const mp4_track_t *p_track,
- const MP4_Box_data_sample_soun_t *p_soun )
+//#define MP4_DEBUG_AUDIO_SAMPLES
+static inline uint32_t MP4_GetAudioFrameInfo( const mp4_track_t *p_track,
+ const MP4_Box_data_sample_soun_t *p_soun,
+ uint32_t *pi_size )
{
- uint32_t i_size = p_track->i_sample_size;
+ uint32_t i_samples_per_frame = p_soun->i_sample_per_packet;
+ uint32_t i_bytes_per_frame = p_soun->i_bytes_per_frame;
- assert( p_track->i_sample_size != 0 );
-
- /* QuickTime "built-in" support case fixups */
- if( p_track->fmt.i_cat == AUDIO_ES &&
- p_soun->i_compressionid == 0 && p_track->i_sample_size <= 2 )
+ switch( p_track->fmt.i_codec )
{
- switch( p_track->fmt.i_codec )
- {
+ /* Quicktime builtin support, _must_ ignore sample tables */
case VLC_CODEC_GSM:
- i_size = p_soun->i_channelcount;
+ i_samples_per_frame = 160;
+ i_bytes_per_frame = 33;
break;
- case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
- case ATOM_twos:
- case ATOM_sowt:
- case ATOM_raw:
+ case VLC_CODEC_ADPCM_IMA_QT:
+ i_samples_per_frame = 64;
+ i_bytes_per_frame = 34 * p_soun->i_channelcount;
+ break;
+ case VLC_CODEC_MACE3:
+ i_samples_per_frame = 6;
+ i_bytes_per_frame = 2 * p_soun->i_channelcount;
+ break;
+ case VLC_CODEC_MACE6:
+ i_samples_per_frame = 6;
+ i_bytes_per_frame = 1 * p_soun->i_channelcount;
+ break;
+ case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
+ i_samples_per_frame = 1;
+ i_bytes_per_frame = p_soun->i_channelcount;
+ break;
+ case VLC_CODEC_ALAW:
case VLC_CODEC_U8:
case VLC_CODEC_S8:
case VLC_CODEC_S16L:
@@ -3612,19 +3623,50 @@ static inline uint32_t MP4_GetFixedSampleSize( const mp4_track_t *p_track,
case VLC_CODEC_F32B:
case VLC_CODEC_F64L:
case VLC_CODEC_F64B:
- if( p_track->i_sample_size < ((p_soun->i_samplesize+7U)/8U) * p_soun->i_channelcount )
- i_size = ((p_soun->i_samplesize+7)/8) * p_soun->i_channelcount;
+ i_samples_per_frame = 1;
+ i_bytes_per_frame = (aout_BitsPerSample( p_track->fmt.i_codec ) *
+ p_soun->i_channelcount) >> 3;
+ assert(i_bytes_per_frame);
break;
- case VLC_CODEC_ALAW:
- case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
- i_size = p_soun->i_channelcount;
+ case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
+ case ATOM_twos:
+ case ATOM_sowt:
+ case ATOM_raw:
+ if( p_soun->i_sample_per_packet && p_soun->i_bytes_per_frame )
+ {
+ i_samples_per_frame = p_soun->i_sample_per_packet;
+ i_bytes_per_frame = p_soun->i_bytes_per_frame;
+ }
+ else
+ {
+ i_samples_per_frame = 1;
+ i_bytes_per_frame = (p_soun->i_samplesize+7) >> 3;
+ i_bytes_per_frame *= p_soun->i_channelcount;
+ }
break;
default:
break;
- }
}
- return i_size;
+ /* Group audio packets so we don't call demux for single sample unit */
+ if( p_track->fmt.i_original_fourcc == VLC_CODEC_DVD_LPCM &&
+ p_soun->i_constLPCMframesperaudiopacket &&
+ p_soun->i_constbytesperaudiopacket )
+ {
+ i_samples_per_frame = p_soun->i_constLPCMframesperaudiopacket;
+ i_bytes_per_frame = p_soun->i_constbytesperaudiopacket;
+ }
+#ifdef MP4_DEBUG_AUDIO_SAMPLES
+ printf("qtv%d comp%x ss %d chan %d ba %d spp %d bpf %d / %d %d\n",
+ p_soun->i_qt_version, p_soun->i_compressionid,
+ p_soun->i_samplesize, p_soun->i_channelcount,
+ p_track->fmt.audio.i_blockalign,
+ p_soun->i_sample_per_packet, p_soun->i_bytes_per_frame,
+ i_samples_per_frame, i_bytes_per_frame);
+#endif
+
+ *pi_size = i_bytes_per_frame;
+ return i_samples_per_frame;
}
static uint32_t MP4_TrackGetReadSize( mp4_track_t *p_track, uint32_t *pi_nb_samples )
@@ -3648,20 +3690,25 @@ static uint32_t MP4_TrackGetReadSize( mp4_track_t *p_track, uint32_t *pi_nb_samp
{
const MP4_Box_data_sample_soun_t *p_soun = p_track->p_sample->data.p_sample_soun;
const mp4_chunk_t *p_chunk = &p_track->chunk[p_track->i_chunk];
- uint32_t i_max_samples = p_chunk->i_sample_count - p_chunk->i_sample;
- /* Group audio packets so we don't call demux for single sample unit */
- if( p_track->fmt.i_original_fourcc == VLC_CODEC_DVD_LPCM &&
- p_soun->i_constLPCMframesperaudiopacket &&
- p_soun->i_constbytesperaudiopacket )
- {
- /* uncompressed case */
- uint32_t i_packets = i_max_samples / p_soun->i_constLPCMframesperaudiopacket;
- if ( UINT32_MAX / p_soun->i_constbytesperaudiopacket < i_packets )
- i_packets = UINT32_MAX / p_soun->i_constbytesperaudiopacket;
- *pi_nb_samples = i_packets * p_soun->i_constLPCMframesperaudiopacket;
- return i_packets * p_soun->i_constbytesperaudiopacket;
- }
+ /* v0:
+ * - isobmff: codec is not using v1 fields
+ * - qt: codec is usually uncompressed and 1 stored sample == 1 byte
+ * and you need to packetize/group samples. hardcoded codecs.
+ * if compressed, samplesize == 16 and codec is also hardcoded (ex: adpcm)
+ * v1:
+ * - samplesize is meaningless, always 16
+ * - compressed frames/packet size parameters applies, but samplesize can
+ * still be bytes. use packet size to deinterleave, but samples per frames
+ * are not the number of stored samples. The chunk can also be a packet in some
+ * (qcelp) cases, in that case we need to return chunk (return 1 stored sample).
+ * If the codec has -2 compression, this is vbr, we can't deinterleave or group
+ * samples at all. (return 1 stored sample)
+ * Again, some hardcoded codecs can exist in qt and we can't trust parameters.
+ * v2:
+ * - lpcm extensions provides additional parameters to group samples, but
+ * 1 stored sample is usually too small in length/bytes, so we need to
+ * packetize group them. Again, 1 stored sample != 1 audio sample. */
if( p_track->fmt.i_original_fourcc == VLC_FOURCC('r','r','t','p') )
{
@@ -3676,60 +3723,14 @@ static uint32_t MP4_TrackGetReadSize( mp4_track_t *p_track, uint32_t *pi_nb_samp
return p_track->p_sample_size[p_track->i_sample];
}
- if( p_soun->i_qt_version == 1 )
+ /* If we are compressed but not v2 LPCM frames extensions */
+ if ( p_soun->i_compressionid == 0xFFFE && p_soun->i_qt_version < 2 )
{
- if ( p_soun->i_compressionid == 0xFFFE )
- {
- *pi_nb_samples = 1; /* != number of audio samples */
- if ( p_track->i_sample_size )
- return p_track->i_sample_size;
- else
- return p_track->p_sample_size[p_track->i_sample];
- }
- else if ( p_soun->i_compressionid != 0 || p_soun->i_bytes_per_sample > 1 ) /* compressed */
- {
- /* in this case we are dealing with compressed data
- -2 in V1: additional fields are meaningless (VBR and such) */
- *pi_nb_samples = i_max_samples;//p_track->chunk[p_track->i_chunk].i_sample_count;
- if( p_track->fmt.audio.i_blockalign > 1 )
- *pi_nb_samples = p_soun->i_sample_per_packet;
- i_size = *pi_nb_samples / p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
- return i_size;
- }
- else /* uncompressed case */
- {
- uint32_t i_packets;
- if( p_track->fmt.audio.i_blockalign > 1 )
- i_packets = 1;
- else
- i_packets = i_max_samples / p_soun->i_sample_per_packet;
-
- if ( UINT32_MAX / p_soun->i_bytes_per_frame < i_packets )
- i_packets = UINT32_MAX / p_soun->i_bytes_per_frame;
-
- *pi_nb_samples = i_packets * p_soun->i_sample_per_packet;
- i_size = i_packets * p_soun->i_bytes_per_frame;
- return i_size;
- }
- }
-
- /* uncompressed v0 (qt) or... not (ISO) */
-
- /* Quicktime built-in support handling */
- if( p_soun->i_compressionid == 0 && p_track->i_sample_size == 1 )
- {
- switch( p_track->fmt.i_codec )
- {
- /* sample size is not integer */
- case VLC_CODEC_GSM:
- *pi_nb_samples = 160 * p_track->fmt.audio.i_channels;
- return 33 * p_track->fmt.audio.i_channels;
- case VLC_CODEC_ADPCM_IMA_QT:
- *pi_nb_samples = 64 * p_track->fmt.audio.i_channels;
- return 34 * p_track->fmt.audio.i_channels;
- default:
- break;
- }
+ *pi_nb_samples = 1; /* != number of audio samples */
+ if ( p_track->i_sample_size )
+ return p_track->i_sample_size;
+ else
+ return p_track->p_sample_size[p_track->i_sample];
}
/* More regular V0 cases */
@@ -3760,30 +3761,70 @@ static uint32_t MP4_TrackGetReadSize( mp4_track_t *p_track, uint32_t *pi_nb_samp
}
*pi_nb_samples = 0;
- for( uint32_t i=p_track->i_sample;
- i<p_chunk->i_sample_first+p_chunk->i_sample_count &&
- i<p_track->i_sample_count;
- i++ )
+
+ if( p_track->i_sample_size > 0 )
{
- (*pi_nb_samples)++;
- if ( p_track->i_sample_size == 0 )
- i_size += p_track->p_sample_size[i];
- else
- i_size += MP4_GetFixedSampleSize( p_track, p_soun );
+ uint32_t i_bytes_per_frame;
+ uint32_t i_samples_per_frame =
+ MP4_GetAudioFrameInfo( p_track, p_soun, &i_bytes_per_frame );
+ uint32_t i_chunk_remaining_samples = p_chunk->i_sample_count -
+ (p_track->i_sample - p_chunk->i_sample_first);
- /* Try to detect compression in ISO */
- if(p_soun->i_compressionid != 0)
+ if( i_max_v0_samples > i_chunk_remaining_samples )
+ i_max_v0_samples = i_chunk_remaining_samples;
+
+ if( i_samples_per_frame && i_bytes_per_frame )
{
- /* Return only 1 sample */
- break;
+ /* GSM, ADPCM, */
+ if( i_samples_per_frame > 64 &&
+ i_samples_per_frame > i_bytes_per_frame )
+ {
+ *pi_nb_samples = i_samples_per_frame;
+ i_size = i_bytes_per_frame;
+ }
+ else
+ {
+ /* Regular cases */
+ uint32_t i_frames = i_max_v0_samples / i_samples_per_frame;
+ *pi_nb_samples = i_frames * i_samples_per_frame;
+ i_size = i_frames * i_bytes_per_frame;
+ }
}
+ else
+ {
+ *pi_nb_samples = 1;
+ return p_track->i_sample_size;
+ }
+#ifdef MP4_DEBUG_AUDIO_SAMPLES
+ printf("demuxing qtv%d comp %x, ss%d, spf %d bpf %d samples %d maxsamples %d remain samples %d\n",
+ p_soun->i_qt_version, p_soun->i_compressionid, p_track->i_sample_size,
+ i_samples_per_frame, i_bytes_per_frame,
+ *pi_nb_samples, i_max_v0_samples, i_chunk_remaining_samples);
+#endif
+ }
+ else /* Compressed */
+ {
+ for( uint32_t i=p_track->i_sample;
+ i<p_chunk->i_sample_first+p_chunk->i_sample_count &&
+ i<p_track->i_sample_count;
+ i++ )
+ {
+ i_size += p_track->p_sample_size[i];
+ (*pi_nb_samples)++;
- if ( *pi_nb_samples == i_max_v0_samples )
- break;
+ /* Try to detect compression in ISO */
+ if(p_soun->i_compressionid != 0)
+ {
+ /* Return only 1 sample */
+ break;
+ }
+
+ if ( *pi_nb_samples == i_max_v0_samples )
+ break;
+ }
}
}
- //fprintf( stderr, "size=%d\n", i_size );
return i_size;
}
@@ -3796,42 +3837,29 @@ static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
if( p_track->i_sample_size )
{
- MP4_Box_data_sample_soun_t *p_soun =
- p_track->p_sample->data.p_sample_soun;
+ /* chunk offset in samples */
+ uint32_t i_samples = p_track->i_sample -
+ p_track->chunk[p_track->i_chunk].i_sample_first;
- /* Quicktime builtin support, _must_ ignore sample tables */
- if( p_track->fmt.i_cat == AUDIO_ES && p_soun->i_compressionid == 0 &&
- p_track->i_sample_size == 1 )
+ if( p_track->fmt.i_cat == AUDIO_ES )
{
- switch( p_track->fmt.i_codec )
+ MP4_Box_data_sample_soun_t *p_soun =
+ p_track->p_sample->data.p_sample_soun;
+
+ if( p_soun->i_compressionid != 0xFFFE )
{
- case VLC_CODEC_GSM: /* # Samples > data size */
- i_pos += ( p_track->i_sample -
- p_track->chunk[p_track->i_chunk].i_sample_first ) / 160 * 33;
- return i_pos;
- case VLC_CODEC_ADPCM_IMA_QT: /* # Samples > data size */
- i_pos += ( p_track->i_sample -
- p_track->chunk[p_track->i_chunk].i_sample_first ) / 64 * 34;
- return i_pos;
- default:
- break;
+ uint32_t i_bytes_per_frame;
+ uint32_t i_samples_per_frame = MP4_GetAudioFrameInfo( p_track, p_soun, &i_bytes_per_frame );
+ if( i_bytes_per_frame && i_samples_per_frame )
+ {
+ /* we read chunk by chunk unless a blockalign is requested */
+ return i_pos + i_samples /
+ i_samples_per_frame * (uint64_t) i_bytes_per_frame;
+ }
}
}
- if( p_track->fmt.i_cat != AUDIO_ES || p_soun->i_qt_version == 0 ||
- p_track->fmt.audio.i_blockalign <= 1 ||
- p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame == 0 )
- {
- i_pos += ( p_track->i_sample -
- p_track->chunk[p_track->i_chunk].i_sample_first ) *
- MP4_GetFixedSampleSize( p_track, p_soun );
- }
- else
- {
- /* we read chunk by chunk unless a blockalign is requested */
- i_pos += ( p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first ) /
- p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
- }
+ i_pos += i_samples * (uint64_t) p_track->i_sample_size;
}
else
{
More information about the vlc-commits
mailing list