[vlc-commits] [Git][videolan/vlc][master] 16 commits: demux: es: rework reading frame header

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Oct 11 07:54:41 UTC 2022



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
e95d07a7 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: rework reading frame header

- - - - -
fa7e7858 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: store frame size in header struct

- - - - -
ad00a35e by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: use frame_samples from header

- - - - -
67f1d4ea by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: rework reading Xing

- - - - -
c08a96bd by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: read Lavc mpga infotag

- - - - -
469fb119 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: parse VBRI

- - - - -
7ef33903 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: skip Xing header

- - - - -
6bd816c9 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: store precomputed track duration

- - - - -
7d0cc3d4 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: have mllt seek check itself

- - - - -
f4563754 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: fix few types

- - - - -
b5b92f73 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: unify seeking

- - - - -
4c80da12 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: add Xing TOC based seeking

- - - - -
b41c65b4 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: use temp var for packetizer

- - - - -
4cfdffe1 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: early set bitrate from Xing header

- - - - -
c534d5d7 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: don't change packetizer fmtout

- - - - -
9dafb994 by Francois Cartegnie at 2022-10-11T07:29:22+00:00
demux: es: set audio channel type

- - - - -


4 changed files:

- modules/access/rtp/mpeg12.c
- modules/demux/mpeg/es.c
- modules/packetizer/mpegaudio.c
- modules/packetizer/mpegaudio.h


Changes:

=====================================
modules/access/rtp/mpeg12.c
=====================================
@@ -141,12 +141,17 @@ static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
 
         /* This RTP payload format does atypically not flag end-of-frames, so
          * we have to parse the MPEG Audio frame header to find out. */
-        unsigned chans, conf, mode, srate, brate, samples, maxsize, layer;
-        int frame_size = SyncInfo(ntoh32(header), &chans, &conf, &mode, &srate,
-                                  &brate, &samples, &maxsize, &layer);
+        struct mpga_frameheader_s fh;
+        if(mpga_decode_frameheader(ntoh32(header), &fh))
+        {
+            vlc_warning(log, "malformatted header");
+            block->i_flags |= BLOCK_FLAG_CORRUPTED;
+            break;
+        }
+
         /* If the frame size is unknown due to free bit rate, then we can only
          * sense the completion of the frame when the next frame starts. */
-        if (frame_size <= 0) {
+        if (fh.i_frame_size == 0) {
             if (sys->offset >= MAX_PACKET_SIZE) {
                 vlc_warning(log, "oversized packet (%zu bytes)", sys->offset);
                 rtp_mpa_send(sys);
@@ -154,14 +159,14 @@ static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
             break;
         }
 
-        if ((size_t)frame_size == sys->offset) {
+        if (fh.i_frame_size == sys->offset) {
             rtp_mpa_send(sys);
             break;
         }
 
         /* If the frame size is larger than the current offset, then we need to
          * wait for the next fragment. */
-        if ((size_t)frame_size > sys->offset)
+        if (fh.i_frame_size > sys->offset)
             break;
 
         if (offset != 0) {
@@ -171,10 +176,10 @@ static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
         }
 
         /* The RTP packet contains multiple small frames. */
-        block_t *frame = block_Alloc(frame_size);
+        block_t *frame = block_Alloc(fh.i_frame_size);
         if (likely(frame != NULL)) {
             assert(block->p_next == NULL); /* Only one block to copy from */
-            memcpy(frame->p_buffer, block->p_buffer, frame_size);
+            memcpy(frame->p_buffer, block->p_buffer, frame->i_buffer);
             frame->i_flags = block->i_flags;
             frame->i_pts = block->i_pts;
             vlc_rtp_es_send(sys->es, frame);
@@ -183,8 +188,8 @@ static void rtp_mpa_decode(struct vlc_rtp_pt *pt, void *data, block_t *block,
         } else
             block->i_flags = BLOCK_FLAG_DISCONTINUITY;
 
-        block->p_buffer += frame_size;
-        block->i_buffer -= frame_size;
+        block->p_buffer += fh.i_frame_size;
+        block->i_buffer -= fh.i_frame_size;
         block->i_pts = VLC_TICK_INVALID;
     }
     return;


=====================================
modules/demux/mpeg/es.c
=====================================
@@ -2,6 +2,7 @@
  * es.c : Generic audio ES input module for vlc
  *****************************************************************************
  * Copyright (C) 2001-2008 VLC authors and VideoLAN
+ *               2022 VideoLabs
  *
  * Authors: Laurent Aimar <fenrir at via.ecp.fr>
  *          Gildas Bazin <gbazin at videolan.org>
@@ -38,6 +39,7 @@
 
 #include "../../packetizer/a52.h"
 #include "../../packetizer/dts_header.h"
+#include "../../packetizer/mpegaudio.h"
 #include "../../meta_engine/ID3Tag.h"
 #include "../../meta_engine/ID3Text.h"
 #include "../../meta_engine/ID3Meta.h"
@@ -96,12 +98,6 @@ typedef struct
     int  (*pf_init)( demux_t *p_demux );
 } codec_t;
 
-typedef struct
-{
-    char  psz_version[10];
-    int   i_lowpass;
-} lame_extra_t;
-
 typedef struct
 {
     vlc_tick_t i_time;
@@ -127,6 +123,211 @@ typedef struct
     seekpoint_t *p_seekpoint;
 } chap_entry_t;
 
+/* Mpga specific */
+#define XING_FIELD_STREAMFRAMES    (1 << 0)
+#define XING_FIELD_STREAMBYTES     (1 << 1)
+#define XING_FIELD_TOC             (1 << 2)
+#define XING_FIELD_QUALITY         (1 << 3)
+#define XING_MIN_TAG_SIZE           42
+#define XING_TOC_COUNTBYTES         100
+#define XING_MAX_TAG_SIZE          (XING_MIN_TAG_SIZE + 4 + 4 + XING_TOC_COUNTBYTES + 4 + 2)
+#define XING_SUB_ETE_NOK_OTAE       XING_MIN_TAG_SIZE
+
+struct xing_info_s
+{
+    uint32_t i_frames;
+    uint32_t i_bytes;
+    uint32_t i_quality;
+    vlc_fourcc_t infotag;
+    vlc_fourcc_t encoder;
+    uint8_t  rgi_toc[XING_TOC_COUNTBYTES];
+    float f_peak_signal;
+    float f_radio_replay_gain;
+    float f_audiophile_replay_gain;
+    enum
+    {
+        XING_MODE_UNKNOWN   = 0,
+        XING_MODE_CBR       = 1,
+        XING_MODE_ABR       = 2,
+        XING_MODE_VBR1      = 3,
+        XING_MODE_VBR2      = 4,
+        XING_MODE_VBR3      = 5,
+        XING_MODE_VBR4      = 6,
+        XING_MODE_CBR_2PASS = 8,
+        XING_MODE_ABR_2PASS = 9,
+    } brmode;
+    enum
+    {
+        XING_AUDIOMODE_UNKNOWN    = 0,
+        XING_AUDIOMODE_DPL        = 1,
+        XING_AUDIOMODE_DPL2       = 2,
+        XING_AUDIOMODE_AMBISONICS = 3,
+    } audiomode;
+    uint8_t  bitrate_avg;
+    uint16_t i_delay_samples;
+    uint16_t i_padding_samples;
+    uint32_t i_music_length;
+};
+
+static int ParseXing( const uint8_t *p_buf, size_t i_buf, struct xing_info_s *xing )
+{
+    if( i_buf < XING_MIN_TAG_SIZE )
+        return VLC_EGENERIC;
+
+    vlc_fourcc_t infotag = VLC_FOURCC(p_buf[0], p_buf[1], p_buf[2], p_buf[3]);
+
+    /* L3Enc VBR info */
+    if( infotag == VLC_FOURCC('V','B','R','I') )
+    {
+        if( GetWBE( &p_buf[4] ) != 0x0001 )
+            return VLC_EGENERIC;
+        xing->i_bytes = GetDWBE( &p_buf[10] );
+        xing->i_frames = GetDWBE( &p_buf[14] );
+        xing->infotag = infotag;
+        return VLC_SUCCESS;
+    }
+    /* Xing VBR/CBR tags */
+    else if( infotag != VLC_FOURCC('X','i','n','g') &&
+             infotag != VLC_FOURCC('I','n','f','o') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    xing->infotag = infotag;
+
+    const uint32_t i_flags = GetDWBE( &p_buf[4] );
+    /* compute our variable struct size for early checks */
+    const unsigned varsz[4] = { ((i_flags & 0x01) ? 4 : 0),
+                                ((i_flags & 0x02) ? 4 : 0),
+                                ((i_flags & 0x04) ? XING_TOC_COUNTBYTES : 0),
+                                ((i_flags & 0x08) ? 4 : 0) };
+    const unsigned i_varallsz = varsz[0] + varsz[1] + varsz[2] + varsz[3];
+    const unsigned i_tag_total = XING_MIN_TAG_SIZE + i_varallsz;
+
+    if( i_buf < i_tag_total )
+        return VLC_EGENERIC;
+
+    if( i_flags & XING_FIELD_STREAMFRAMES )
+        xing->i_frames = GetDWBE( &p_buf[8] );
+    if( i_flags & XING_FIELD_STREAMBYTES )
+        xing->i_bytes = GetDWBE( &p_buf[8 + varsz[0]] );
+    if( i_flags & XING_FIELD_TOC )
+        memcpy( xing->rgi_toc, &p_buf[8 + varsz[0] + varsz[1]], XING_TOC_COUNTBYTES );
+    if( i_flags & XING_FIELD_QUALITY )
+        xing->i_quality = GetDWBE( &p_buf[8 + varsz[0] + varsz[1] + varsz[2]] );
+
+    /* pointer past optional members */
+    const uint8_t *p_fixed = &p_buf[8 + i_varallsz];
+
+    /* Original Xing encoder header stops here */
+
+    xing->encoder = VLC_FOURCC(p_fixed[0], p_fixed[1], p_fixed[2], p_fixed[3]); /* char version[9] start */
+
+    if( xing->encoder != VLC_FOURCC('L','A','M','E') &&
+        xing->encoder != VLC_FOURCC('L','a','v','c') &&
+        xing->encoder != VLC_FOURCC('L','a','v','f') )
+        return VLC_SUCCESS;
+
+    xing->brmode  = p_fixed[8] & 0x0f; /* version upper / mode lower */
+    uint32_t peak_signal  = GetDWBE( &p_fixed[11] );
+    xing->f_peak_signal = peak_signal / 8388608.0; /* pow(2, 23) */
+    uint16_t gain = GetWBE( &p_fixed[15] );
+    xing->f_radio_replay_gain = (gain & 0x1FF) / /* 9bits val stored x10 */
+                                ((gain & 0x200) ? -10.0 : 10.0); /* -sign bit on bit 6 */
+    gain = GetWBE( &p_fixed[17] );
+    xing->f_radio_replay_gain = (gain & 0x1FF) / /* 9bits val stored x10 */
+                                ((gain & 0x200) ? -10.0 : 10.0); /* -sign bit on bit 6 */
+    /* flags @19 */
+    xing->bitrate_avg = (p_fixed[20] != 0xFF) ? p_fixed[20] : 0; /* clipped to 255, so it's unknown from there */
+    xing->i_delay_samples = (p_fixed[21] << 4) | (p_fixed[22] >> 4); /* upper 12bits */
+    xing->i_padding_samples = ((p_fixed[22] & 0x0F) << 8) | p_fixed[23]; /* lower 12bits */
+    xing->audiomode = (p_fixed[26] >> 3) & 0x07; /* over 16bits, 2b unused / 3b mode / 11b preset */
+    xing->i_music_length  = GetDWBE( &p_fixed[28] );
+
+    return VLC_SUCCESS;
+}
+
+static int MpgaGetCBRSeekpoint( const struct mpga_frameheader_s *mpgah,
+                                const struct xing_info_s *xing,
+                                uint64_t i_seekablesize,
+                                double f_pos, vlc_tick_t *pi_time, uint64_t *pi_offset )
+{
+    if( xing->infotag != 0 &&
+        xing->infotag != VLC_FOURCC('I','n','f','o') &&
+        xing->brmode != XING_MODE_CBR &&
+        xing->brmode != XING_MODE_CBR_2PASS )
+        return -1;
+
+    if( !mpgah->i_sample_rate || !mpgah->i_samples_per_frame || !mpgah->i_frame_size )
+        return -1;
+
+    uint32_t i_total_frames = xing->i_frames ? xing->i_frames
+                                             : i_seekablesize / mpgah->i_frame_size;
+
+    /* xing must be optional here */
+    uint32_t i_frame = i_total_frames * f_pos;
+    *pi_offset = i_frame * mpgah->i_frame_size;
+    *pi_time = vlc_tick_from_samples( i_frame * mpgah->i_samples_per_frame,
+                                      mpgah->i_sample_rate ) + VLC_TICK_0;
+
+    return 0;
+}
+
+static int SeekByPosUsingXingTOC( const struct mpga_frameheader_s *mpgah,
+                                  const struct xing_info_s *xing,double pos,
+                                  vlc_tick_t *pi_time, uint64_t *pi_offset )
+{
+    if( !xing->rgi_toc[XING_TOC_COUNTBYTES - 1] ||
+        !mpgah->i_sample_rate || !mpgah->i_samples_per_frame )
+        return -1;
+
+    unsigned syncentry = pos * XING_TOC_COUNTBYTES;
+    syncentry = VLC_CLIP(syncentry, 0, XING_TOC_COUNTBYTES - 1);
+    unsigned syncframe = syncentry * xing->i_frames / XING_TOC_COUNTBYTES;
+
+    *pi_time = vlc_tick_from_samples( syncframe * mpgah->i_samples_per_frame,
+                                      mpgah->i_sample_rate ) + VLC_TICK_0;
+    *pi_offset = xing->rgi_toc[syncentry] * xing->i_bytes / 256;
+
+    return 0;
+}
+
+static int SeekByTimeUsingXingTOC( const struct mpga_frameheader_s *mpgah,
+                                   const struct xing_info_s *xing,
+                                   vlc_tick_t *pi_time, uint64_t *pi_offset )
+{
+    if( !mpgah->i_sample_rate || !mpgah->i_samples_per_frame || !xing->i_frames ||
+        *pi_time < VLC_TICK_0 )
+        return -1;
+
+    uint32_t sample = samples_from_vlc_tick( *pi_time - VLC_TICK_0, mpgah->i_sample_rate );
+    uint64_t totalsamples = mpgah->i_samples_per_frame * (uint64_t) xing->i_frames;
+
+    return SeekByPosUsingXingTOC( mpgah, xing, (double)sample / totalsamples,
+                                  pi_time, pi_offset );
+}
+
+static int MpgaSeek( const struct mpga_frameheader_s *mpgah,
+                     const struct xing_info_s *xing,
+                     uint64_t i_seekablesize, double f_pos,
+                     vlc_tick_t *pi_time, uint64_t *pi_offset )
+{
+    if( f_pos >= 0 ) /* Set Pos */
+    {
+        if( !MpgaGetCBRSeekpoint( mpgah, xing, i_seekablesize,
+                                  f_pos, pi_time, pi_offset ) )
+        {
+             return 0;
+        }
+    }
+
+    if( *pi_time != VLC_TICK_INVALID &&
+        !SeekByTimeUsingXingTOC( mpgah, xing, pi_time, pi_offset ) )
+        return 0;
+
+    return SeekByPosUsingXingTOC( mpgah, xing, f_pos, pi_time, pi_offset );
+}
+
 typedef struct
 {
     codec_t codec;
@@ -140,15 +341,16 @@ typedef struct
 
     vlc_tick_t  i_pts;
     vlc_tick_t  i_time_offset;
-    int64_t     i_bytes;
+    uint64_t    i_bytes;
 
     bool        b_big_endian;
     bool        b_estimate_bitrate;
-    int         i_bitrate_avg;  /* extracted from Xing header */
+    unsigned    i_bitrate;  /* extracted from Xing header */
+    vlc_tick_t  i_duration;
 
     bool b_initial_sync_failed;
 
-    int i_packet_size;
+    unsigned i_packet_size;
 
     uint64_t i_stream_offset;
     unsigned i_demux_flags;
@@ -156,15 +358,8 @@ typedef struct
     float   f_fps;
 
     /* Mpga specific */
-    struct
-    {
-        int i_frames;
-        int i_bytes;
-        int i_bitrate_avg;
-        int i_frame_samples;
-        lame_extra_t lame;
-        bool b_lame;
-    } xing;
+    struct mpga_frameheader_s mpgah;
+    struct xing_info_s xing;
 
     float rgf_replay_gain[AUDIO_REPLAY_GAIN_MAX];
     float rgf_replay_peak[AUDIO_REPLAY_GAIN_MAX];
@@ -196,7 +391,7 @@ static int ThdProbe( demux_t *p_demux, uint64_t *pi_offset );
 static int MlpInit( demux_t *p_demux );
 
 static bool Parse( demux_t *p_demux, block_t **pp_output );
-static uint64_t SeekByMlltTable( demux_t *p_demux, vlc_tick_t *pi_time );
+static int SeekByMlltTable( sync_table_t *, vlc_tick_t *, uint64_t * );
 
 static const codec_t p_codecs[] = {
     { VLC_CODEC_MP4A, false, "mp4 audio",  AacProbe,  AacInit },
@@ -233,7 +428,8 @@ static int OpenCommon( demux_t *p_demux,
     p_sys->b_start = true;
     p_sys->i_stream_offset = i_bs_offset;
     p_sys->b_estimate_bitrate = true;
-    p_sys->i_bitrate_avg = 0;
+    p_sys->i_bitrate = 0;
+    p_sys->i_duration = 0;
     p_sys->b_big_endian = false;
     p_sys->f_fps = var_InheritFloat( p_demux, "es-fps" );
     p_sys->p_packetized_data = NULL;
@@ -252,6 +448,12 @@ static int OpenCommon( demux_t *p_demux,
         return VLC_EGENERIC;
     }
 
+    if( vlc_stream_Seek( p_demux->s, p_sys->i_stream_offset ) )
+    {
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+
     msg_Dbg( p_demux, "detected format %4.4s", (const char*)&p_sys->codec.i_codec );
 
     /* Load the audio packetizer */
@@ -391,7 +593,7 @@ static int Demux( demux_t *p_demux )
         }
         /* Re-estimate bitrate */
         if( p_sys->b_estimate_bitrate && p_sys->i_pts > VLC_TICK_FROM_MS(500) )
-            p_sys->i_bitrate_avg = 8 * CLOCK_FREQ * p_sys->i_bytes
+            p_sys->i_bitrate = 8 * CLOCK_FREQ * p_sys->i_bytes
                                    / (p_sys->i_pts - 1);
         p_sys->i_bytes += p_block_out->i_buffer;
 
@@ -426,19 +628,27 @@ static void Close( vlc_object_t * p_this )
 /*****************************************************************************
  * Time seek:
  *****************************************************************************/
-static int MovetoTimePos( demux_t *p_demux, vlc_tick_t i_time, uint64_t i_pos )
+static void PostSeekCleanup( demux_sys_t *p_sys, vlc_tick_t i_time )
 {
-    demux_sys_t *p_sys  = p_demux->p_sys;
-    int i_ret = vlc_stream_Seek( p_demux->s, p_sys->i_stream_offset + i_pos );
-    if( i_ret != VLC_SUCCESS )
-        return i_ret;
-    p_sys->i_time_offset = i_time - p_sys->i_pts;
+    /* Fix time_offset */
+    if( i_time >= 0 )
+        p_sys->i_time_offset = i_time - p_sys->i_pts;
     /* And reset buffered data */
     if( p_sys->p_packetized_data )
         block_ChainRelease( p_sys->p_packetized_data );
     p_sys->p_packetized_data = NULL;
+    /* Reset chapter if any */
     p_sys->chapters.i_current = 0;
     p_sys->i_demux_flags |= INPUT_UPDATE_SEEKPOINT;
+}
+
+static int MovetoTimePos( demux_t *p_demux, vlc_tick_t i_time, uint64_t i_pos )
+{
+    demux_sys_t *p_sys  = p_demux->p_sys;
+    int i_ret = vlc_stream_Seek( p_demux->s, p_sys->i_stream_offset + i_pos );
+    if( i_ret != VLC_SUCCESS )
+        return i_ret;
+    PostSeekCleanup( p_sys, i_time );
     return VLC_SUCCESS;
 }
 
@@ -463,17 +673,23 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
 
         case DEMUX_GET_LENGTH:
         {
+            if( p_sys->i_duration > 0 )
+            {
+                *va_arg( args, vlc_tick_t * ) = p_sys->i_duration;
+                return VLC_SUCCESS;
+            }
+            /* compute length from bitrate */
             va_list ap;
             int i_ret;
 
             va_copy ( ap, args );
             i_ret = demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset,
-                                    -1, p_sys->i_bitrate_avg, 1, i_query, ap );
+                                    -1, p_sys->i_bitrate, 1, i_query, ap );
             va_end( ap );
 
             /* No bitrate, we can't have it precisely, but we can compute
              * a raw approximation with time/position */
-            if( i_ret && !p_sys->i_bitrate_avg )
+            if( i_ret && !p_sys->i_bitrate )
             {
                 float f_pos = (double)(uint64_t)( vlc_stream_Tell( p_demux->s ) ) /
                               (double)(uint64_t)( stream_Size( p_demux->s ) );
@@ -493,15 +709,71 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
         }
 
         case DEMUX_SET_TIME:
-            if( p_sys->mllt.p_bits )
+        case DEMUX_SET_POSITION:
+        {
+            vlc_tick_t i_time;
+            double f_pos;
+            uint64_t i_offset;
+
+            va_list ap;
+            va_copy ( ap, args ); /* don't break args for helper fallback */
+            if( i_query == DEMUX_SET_TIME )
+            {
+                i_time = va_arg(ap, vlc_tick_t);
+                f_pos = p_sys->i_duration ? i_time / (double) p_sys->i_duration : -1.0;
+                if( f_pos > 1.0 )
+                    f_pos = 1.0;
+            }
+            else
+            {
+                f_pos = va_arg(ap, double);
+                i_time = p_sys->i_duration ? p_sys->i_duration * f_pos : VLC_TICK_INVALID;
+            }
+            va_end( ap );
+
+            /* Try to use ID3 table */
+            if( !SeekByMlltTable( &p_sys->mllt, &i_time, &i_offset ) )
+                return MovetoTimePos( p_demux, i_time, i_offset );
+
+            if( p_sys->codec.i_codec == VLC_CODEC_MPGA )
             {
-                vlc_tick_t i_time = va_arg(args, vlc_tick_t);
-                uint64_t i_pos = SeekByMlltTable( p_demux, &i_time );
-                return MovetoTimePos( p_demux, i_time, i_pos );
+                uint64_t streamsize;
+                if( !vlc_stream_GetSize( p_demux->s, &streamsize ) &&
+                    streamsize > p_sys->i_stream_offset )
+                    streamsize -= p_sys->i_stream_offset;
+                else
+                    streamsize = 0;
+
+                if( !MpgaSeek( &p_sys->mpgah, &p_sys->xing,
+                           streamsize, f_pos, &i_time, &i_offset ) )
+                {
+                    return MovetoTimePos( p_demux, i_time, i_offset );
+                }
             }
+
+            /* fallback on bitrate / file position seeking */
+            i_time = VLC_TICK_INVALID;
+            int ret = demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset, -1,
+                                             p_sys->i_bitrate, 1, i_query, args );
+            if( ret != VLC_SUCCESS )
+                return ret; /* not much we can do */
+
+            if( p_sys->i_bitrate > 0 )
+            {
+                i_offset = vlc_stream_Tell( p_demux->s ); /* new pos */
+                i_time = VLC_TICK_0;
+                if( likely(i_offset > p_sys->i_stream_offset) )
+                {
+                    i_offset -= p_sys->i_stream_offset;
+                    i_time += vlc_tick_from_samples( i_offset * 8, p_sys->i_bitrate );
+                }
+            }
+            PostSeekCleanup( p_sys, i_time );
+
             /* FIXME TODO: implement a high precision seek (with mp3 parsing)
              * needed for multi-input */
-            break;
+            return VLC_SUCCESS;
+        }
 
         case DEMUX_GET_TITLE_INFO:
         {
@@ -575,34 +847,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
         }
     }
 
-    int ret = demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset, -1,
-                                       p_sys->i_bitrate_avg, 1, i_query, args );
-    if( ret != VLC_SUCCESS )
-        return ret;
-
-    if( i_query == DEMUX_SET_POSITION || i_query == DEMUX_SET_TIME )
-    {
-        if( p_sys->i_bitrate_avg > 0 )
-        {
-            vlc_tick_t i_time = vlc_tick_from_samples(
-                ( vlc_stream_Tell(p_demux->s) - p_sys->i_stream_offset ) * 8
-                , p_sys->i_bitrate_avg );
-
-            /* Fix time_offset */
-            if( i_time >= 0 )
-                p_sys->i_time_offset = i_time - p_sys->i_pts;
-            /* And reset buffered data */
-            if( p_sys->p_packetized_data )
-                block_ChainRelease( p_sys->p_packetized_data );
-            p_sys->p_packetized_data = NULL;
-        }
-
-        /* Reset chapter if any */
-        p_sys->chapters.i_current = 0;
-        p_sys->i_demux_flags |= INPUT_UPDATE_SEEKPOINT;
-    }
-
-    return VLC_SUCCESS;
+    return demux_vaControlHelper( p_demux->s, p_sys->i_stream_offset, -1,
+                                  p_sys->i_bitrate, 1, i_query, args );
 }
 
 /*****************************************************************************
@@ -651,33 +897,36 @@ static bool Parse( demux_t *p_demux, block_t **pp_output )
     }
     p_sys->b_initial_sync_failed = p_sys->b_start; /* Only try to resync once */
 
-    while( ( p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, p_block_in ? &p_block_in : NULL ) ) )
+    decoder_t *p_packetizer = p_sys->p_packetizer;
+    while( ( p_block_out = p_packetizer->pf_packetize( p_packetizer, p_block_in ? &p_block_in : NULL ) ) )
     {
         p_sys->b_initial_sync_failed = false;
         while( p_block_out )
         {
             if( !p_sys->p_es )
             {
-                p_sys->p_packetizer->fmt_out.b_packetized = true;
-                p_sys->p_packetizer->fmt_out.i_id = 0;
-                p_sys->p_es = es_out_Add( p_demux->out,
-                                          &p_sys->p_packetizer->fmt_out);
-
+                es_format_t fmt;
+                es_format_Init( &fmt, p_packetizer->fmt_out.i_cat, p_packetizer->fmt_out.i_codec );
+                es_format_Copy( &fmt, &p_packetizer->fmt_out );
 
-                /* Try the xing header */
-                if( p_sys->xing.i_bytes && p_sys->xing.i_frames &&
-                    p_sys->xing.i_frame_samples )
+                switch( p_sys->xing.audiomode )
                 {
-                    p_sys->i_bitrate_avg = p_sys->xing.i_bytes * INT64_C(8) *
-                        p_sys->p_packetizer->fmt_out.audio.i_rate /
-                        p_sys->xing.i_frames / p_sys->xing.i_frame_samples;
-
-                    if( p_sys->i_bitrate_avg > 0 )
-                        p_sys->b_estimate_bitrate = false;
+                    case XING_AUDIOMODE_AMBISONICS:
+                        fmt.audio.channel_type = AUDIO_CHANNEL_TYPE_AMBISONICS;
+                        break;
+                    default:
+                        break;
                 }
+
+                fmt.b_packetized = true;
+                fmt.i_id = 0;
+                p_sys->p_es = es_out_Add( p_demux->out, &fmt );
+
                 /* Use the bitrate as initual value */
                 if( p_sys->b_estimate_bitrate )
-                    p_sys->i_bitrate_avg = p_sys->p_packetizer->fmt_out.i_bitrate;
+                    p_sys->i_bitrate = fmt.i_bitrate;
+
+                es_format_Clean( &fmt );
             }
 
             block_t *p_next = p_block_out->p_next;
@@ -896,22 +1145,6 @@ static int MpgaCheckSync( const uint8_t *p_peek )
 #define MPGA_VERSION( h )   ( 1 - (((h)>>19)&0x01) )
 #define MPGA_MODE(h)        (((h)>> 6)&0x03)
 
-static int MpgaGetFrameSamples( uint32_t h )
-{
-    const int i_layer = 3 - (((h)>>17)&0x03);
-    switch( i_layer )
-    {
-    case 0:
-        return 384;
-    case 1:
-        return 1152;
-    case 2:
-        return MPGA_VERSION(h) ? 576 : 1152;
-    default:
-        return 0;
-    }
-}
-
 static int MpgaProbe( demux_t *p_demux, uint64_t *pi_offset )
 {
     const uint16_t rgi_twocc[] = { WAVE_FORMAT_MPEG, WAVE_FORMAT_MPEGLAYER3, WAVE_FORMAT_UNKNOWN };
@@ -965,78 +1198,37 @@ static int MpgaProbe( demux_t *p_demux, uint64_t *pi_offset )
     return VLC_SUCCESS;
 }
 
-static void MpgaXingSkip( const uint8_t **pp_xing, int *pi_xing, int i_count )
-{
-    if(i_count > *pi_xing )
-        i_count = *pi_xing;
-
-    (*pp_xing) += i_count;
-    (*pi_xing) -= i_count;
-}
-
-static uint32_t MpgaXingGetDWBE( const uint8_t **pp_xing, int *pi_xing, uint32_t i_default )
-{
-    if( *pi_xing < 4 )
-        return i_default;
-
-    uint32_t v = GetDWBE( *pp_xing );
-
-    MpgaXingSkip( pp_xing, pi_xing, 4 );
-
-    return v;
-}
-
-static uint16_t MpgaXingGetWBE( const uint8_t **pp_xing, int *pi_xing, uint16_t i_default )
-{
-    if( *pi_xing < 2 )
-        return i_default;
-
-    uint16_t v = GetWBE( *pp_xing );
-
-    MpgaXingSkip( pp_xing, pi_xing, 2 );
-
-    return v;
-}
-
-static double MpgaXingLameConvertGain( uint16_t x )
-{
-    double gain = (x & 0x1FF) / 10.0;
-
-    return x & 0x200 ? -gain : gain;
-}
-
-static double MpgaXingLameConvertPeak( uint32_t x )
+static int SeekByMlltTable( sync_table_t *mllt, vlc_tick_t *pi_time, uint64_t *pi_offset )
 {
-    return x / 8388608.0; /* pow(2, 23) */
-}
+    if( !mllt->p_bits )
+        return -1;
 
-static uint64_t SeekByMlltTable( demux_t *p_demux, vlc_tick_t *pi_time )
-{
-    demux_sys_t *p_sys = p_demux->p_sys;
-    sync_table_ctx_t *p_cur = &p_sys->mllt.current;
+    sync_table_ctx_t *p_cur = &mllt->current;
 
     /* reset or init context */
     if( *pi_time < p_cur->i_time || !p_cur->br.p )
     {
         p_cur->i_time = 0;
         p_cur->i_pos = 0;
-        bs_init(&p_cur->br, p_sys->mllt.p_bits, p_sys->mllt.i_bits);
+        bs_init(&p_cur->br, mllt->p_bits, mllt->i_bits);
     }
 
     while(!bs_eof(&p_cur->br))
     {
-        const uint32_t i_bytesdev = bs_read(&p_cur->br, p_sys->mllt.i_bits_per_bytes_dev);
-        const uint32_t i_msdev = bs_read(&p_cur->br, p_sys->mllt.i_bits_per_ms_dev);
+        const uint32_t i_bytesdev = bs_read(&p_cur->br, mllt->i_bits_per_bytes_dev);
+        const uint32_t i_msdev = bs_read(&p_cur->br, mllt->i_bits_per_ms_dev);
         if(bs_error(&p_cur->br))
             break;
-        const vlc_tick_t i_deltatime = VLC_TICK_FROM_MS(p_sys->mllt.i_ms_btw_refs + i_msdev);
+        const vlc_tick_t i_deltatime = VLC_TICK_FROM_MS(mllt->i_ms_btw_refs + i_msdev);
         if( p_cur->i_time + i_deltatime > *pi_time )
             break;
         p_cur->i_time += i_deltatime;
-        p_cur->i_pos += p_sys->mllt.i_bytes_btw_refs + i_bytesdev;
+        p_cur->i_pos += mllt->i_bytes_btw_refs + i_bytesdev;
     }
     *pi_time = p_cur->i_time;
-    return p_cur->i_pos;
+    *pi_offset = p_cur->i_pos;
+
+    return 0;
 }
 
 static int ID3TAG_Parse_Handler( uint32_t i_tag, const uint8_t *p_payload, size_t i_payload, void *p_priv )
@@ -1172,12 +1364,10 @@ static int MpgaInit( demux_t *p_demux )
         return VLC_SUCCESS;
 
     const uint32_t header = GetDWBE( p_peek );
-    if( !MpgaCheckSync( p_peek ) )
+    if( !MpgaCheckSync( p_peek ) || mpga_decode_frameheader( header, &p_sys->mpgah ) )
         return VLC_SUCCESS;
 
     /* Xing header */
-    const uint8_t *p_xing = p_peek;
-    int i_xing = i_peek;
     int i_skip;
 
     if( MPGA_VERSION( header ) == 0 )
@@ -1185,60 +1375,60 @@ static int MpgaInit( demux_t *p_demux )
     else
         i_skip = MPGA_MODE( header ) != 3 ? 21 : 13;
 
-    if( i_skip + 8 >= i_xing || memcmp( &p_xing[i_skip], "Xing", 4 ) )
+    if( i_skip >= i_peek )
         return VLC_SUCCESS;
 
-    const uint32_t i_flags = GetDWBE( &p_xing[i_skip+4] );
-
-    MpgaXingSkip( &p_xing, &i_xing, i_skip + 8 );
-
-    if( i_flags&0x01 )
-        p_sys->xing.i_frames = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
-    if( i_flags&0x02 )
-        p_sys->xing.i_bytes = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
-    if( i_flags&0x04 ) /* TODO Support XING TOC to improve seeking accuracy */
-        MpgaXingSkip( &p_xing, &i_xing, 100 );
-    if( i_flags&0x08 )
-    {
-        /* FIXME: doesn't return the right bitrage average, at least
-           with some MP3's */
-        p_sys->xing.i_bitrate_avg = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
-        msg_Dbg( p_demux, "xing vbr value present (%d)",
-                 p_sys->xing.i_bitrate_avg );
-    }
-
-    if( p_sys->xing.i_frames > 0 && p_sys->xing.i_bytes > 0 )
+    struct xing_info_s *xing = &p_sys->xing;
+    if( ParseXing( &p_peek[i_skip], i_peek - i_skip, xing ) == VLC_SUCCESS )
     {
-        p_sys->xing.i_frame_samples = MpgaGetFrameSamples( header );
-        msg_Dbg( p_demux, "xing frames&bytes value present "
-                 "(%d bytes, %d frames, %d samples/frame)",
-                 p_sys->xing.i_bytes, p_sys->xing.i_frames,
-                 p_sys->xing.i_frame_samples );
-    }
+        const uint64_t i_total_samples = xing->i_frames * (uint64_t) p_sys->mpgah.i_samples_per_frame;
+        const uint64_t i_dropped_samples = xing->i_delay_samples + xing->i_padding_samples;
 
-    if( i_xing >= 20 && memcmp( p_xing, "LAME", 4 ) == 0)
-    {
-        p_sys->xing.b_lame = true;
-        lame_extra_t *p_lame = &p_sys->xing.lame;
+        if( p_sys->mpgah.i_sample_rate && i_dropped_samples < i_total_samples )
+        {
+            uint64_t i_stream_size;
+            /* We only set duration if we can't check (then compute it using bitrate/size)
+               or if we verified the file isn't truncated */
+            if( xing->i_bytes == 0 ||
+                vlc_stream_GetSize( p_demux->s, &i_stream_size ) ||
+                i_stream_size >= xing->i_bytes + p_sys->mpgah.i_frame_size )
+            {
+                p_sys->i_duration = vlc_tick_from_samples( i_total_samples - i_dropped_samples,
+                                                           p_sys->mpgah.i_sample_rate );
+            }
+        }
 
-        memcpy( p_lame->psz_version, p_xing, 9 );
-        p_lame->psz_version[9] = '\0';
+        unsigned i_bitrate = 0;
+        if( xing->brmode == XING_MODE_ABR || xing->brmode == XING_MODE_ABR_2PASS )
+            i_bitrate = xing->bitrate_avg * 1000;
 
-        MpgaXingSkip( &p_xing, &i_xing, 9 );
-        MpgaXingSkip( &p_xing, &i_xing, 1 ); /* rev_method */
+        if( !i_bitrate && p_sys->mpgah.i_sample_rate &&
+            xing->i_bytes > p_sys->mpgah.i_frame_size )
+        {
+            unsigned d = vlc_tick_from_samples( i_total_samples, p_sys->mpgah.i_sample_rate );
+            if( d )
+                i_bitrate = (xing->i_bytes - p_sys->mpgah.i_frame_size) * 8 * CLOCK_FREQ / d;
+        }
 
-        p_lame->i_lowpass = (*p_xing) * 100;
-        MpgaXingSkip( &p_xing, &i_xing, 1 );
+        if( i_bitrate )
+        {
+            p_sys->i_bitrate = i_bitrate;
+            p_sys->b_estimate_bitrate = false;
+        }
 
-        uint32_t peak  = MpgaXingGetDWBE( &p_xing, &i_xing, 0 );
-        uint16_t track = MpgaXingGetWBE( &p_xing, &i_xing, 0 );
-        uint16_t album = MpgaXingGetWBE( &p_xing, &i_xing, 0 );
+        p_sys->rgf_replay_peak[AUDIO_REPLAY_GAIN_TRACK] = xing->f_peak_signal;
+        p_sys->rgf_replay_gain[AUDIO_REPLAY_GAIN_TRACK] = xing->f_radio_replay_gain;
+        p_sys->rgf_replay_gain[AUDIO_REPLAY_GAIN_ALBUM] = xing->f_audiophile_replay_gain;
 
-        p_sys->rgf_replay_peak[AUDIO_REPLAY_GAIN_TRACK] = (float) MpgaXingLameConvertPeak( peak );
-        p_sys->rgf_replay_gain[AUDIO_REPLAY_GAIN_TRACK] = (float) MpgaXingLameConvertGain( track );
-        p_sys->rgf_replay_gain[AUDIO_REPLAY_GAIN_ALBUM] = (float) MpgaXingLameConvertGain( album );
+        msg_Dbg( p_demux, "Using '%4.4s' infotag"
+                          "(%"PRIu32" bytes, %"PRIu32" frames, %u samples/frame)",
+                          (char *) &xing->infotag,
+                          xing->i_bytes, xing->i_frames,
+                          p_sys->mpgah.i_samples_per_frame );
 
-        MpgaXingSkip( &p_xing, &i_xing, 1 ); /* flags */
+        /* We'll need to skip that part for playback
+         * and avoid using it as container frame could be different rate/size */
+        p_sys->i_stream_offset += p_sys->mpgah.i_frame_size;
     }
 
     return VLC_SUCCESS;


=====================================
modules/packetizer/mpegaudio.c
=====================================
@@ -61,10 +61,8 @@ typedef struct
 
     vlc_tick_t i_pts;
 
-    int i_frame_size, i_free_frame_size;
-    unsigned int i_channels_conf, i_chan_mode, i_channels;
-    unsigned int i_rate, i_max_frame_size, i_frame_length;
-    unsigned int i_layer, i_bit_rate;
+    unsigned int i_free_frame_size;
+    struct mpga_frameheader_s header;
 
     bool   b_discontinuity;
 } decoder_sys_t;
@@ -109,37 +107,38 @@ static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate ||
+    if( p_dec->fmt_out.audio.i_rate != p_sys->header.i_sample_rate ||
         date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
     {
-        msg_Dbg( p_dec, "MPGA channels:%d samplerate:%d bitrate:%d",
-                  p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
+        msg_Dbg( p_dec, "MPGA channels:%"PRIu8" samplerate:%u bitrate:%"PRIu16,
+                 p_sys->header.i_channels, p_sys->header.i_sample_rate,
+                 p_sys->header.i_bit_rate );
 
         if( p_sys->end_date.i_divider_num == 0 )
-            date_Init( &p_sys->end_date, p_sys->i_rate, 1 );
+            date_Init( &p_sys->end_date, p_sys->header.i_sample_rate, 1 );
         else
-            date_Change( &p_sys->end_date, p_sys->i_rate, 1 );
+            date_Change( &p_sys->end_date, p_sys->header.i_sample_rate, 1 );
         date_Set( &p_sys->end_date, p_sys->i_pts );
     }
 
-    p_dec->fmt_out.i_profile        = p_sys->i_layer;
-    p_dec->fmt_out.audio.i_rate     = p_sys->i_rate;
-    p_dec->fmt_out.audio.i_channels = p_sys->i_channels;
-    p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length;
-    p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_max_frame_size;
+    p_dec->fmt_out.i_profile        = p_sys->header.i_layer;
+    p_dec->fmt_out.audio.i_rate     = p_sys->header.i_sample_rate;
+    p_dec->fmt_out.audio.i_channels = p_sys->header.i_channels;
+    p_dec->fmt_out.audio.i_frame_length = p_sys->header.i_samples_per_frame;
+    p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->header.i_max_frame_size;
 
-    p_dec->fmt_out.audio.i_physical_channels = p_sys->i_channels_conf;
-    p_dec->fmt_out.audio.i_chan_mode = p_sys->i_chan_mode;
+    p_dec->fmt_out.audio.i_physical_channels = p_sys->header.i_channels_conf;
+    p_dec->fmt_out.audio.i_chan_mode = p_sys->header.i_chan_mode;
 
-    p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate * 1000;
+    p_dec->fmt_out.i_bitrate = p_sys->header.i_bit_rate * 1000U;
 
-    block_t *p_block = block_Alloc( p_sys->i_frame_size );
+    block_t *p_block = block_Alloc( p_sys->header.i_frame_size );
     if( p_block == NULL )
         return NULL;
 
     p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
     p_block->i_length =
-        date_Increment( &p_sys->end_date, p_sys->i_frame_length ) - p_block->i_pts;
+        date_Increment( &p_sys->end_date, p_sys->header.i_samples_per_frame ) - p_block->i_pts;
 
     *pp_out_buffer = p_block;
     return p_block->p_buffer;
@@ -248,17 +247,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             i_header = GetDWBE(p_header);
 
             /* Check if frame is valid and get frame info */
-            p_sys->i_frame_size = SyncInfo( i_header,
-                                            &p_sys->i_channels,
-                                            &p_sys->i_channels_conf,
-                                            &p_sys->i_chan_mode,
-                                            &p_sys->i_rate,
-                                            &p_sys->i_bit_rate,
-                                            &p_sys->i_frame_length,
-                                            &p_sys->i_max_frame_size,
-                                            &p_sys->i_layer );
-
-            if( p_sys->i_frame_size == -1 )
+            if( mpga_decode_frameheader( i_header, &p_sys->header ) )
             {
                 msg_Dbg( p_dec, "emulated startcode" );
                 block_SkipByte( &p_sys->bytestream );
@@ -266,7 +255,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 break;
             }
 
-            if( p_sys->i_bit_rate == 0 )
+            if( p_sys->header.i_bit_rate == 0 )
             {
                 /* Free bitrate, but 99% emulated startcode :( */
                 if( p_sys->i_free_frame_size == MPGA_HEADER_SIZE )
@@ -274,7 +263,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                     msg_Dbg( p_dec, "free bitrate mode");
                 }
                 /* The -1 below is to account for the frame padding */
-                p_sys->i_frame_size = p_sys->i_free_frame_size - 1;
+                p_sys->header.i_frame_size = p_sys->i_free_frame_size - 1;
             }
 
             p_sys->i_state = STATE_NEXT_SYNC;
@@ -283,7 +272,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         case STATE_NEXT_SYNC:
             /* Check if next expected frame contains the sync word */
             if( block_PeekOffsetBytes( &p_sys->bytestream,
-                                       p_sys->i_frame_size, p_header,
+                                       p_sys->header.i_frame_size, p_header,
                                        MAD_BUFFER_GUARD ) != VLC_SUCCESS )
             {
                 if( p_block == NULL ) /* drain */
@@ -298,63 +287,51 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             if( p_header[0] == 0xff && (p_header[1] & 0xe0) == 0xe0 )
             {
                 /* Startcode is fine, let's try the header as an extra check */
-                int i_next_frame_size;
-                unsigned int i_next_channels, i_next_stereo_mode, i_next_channels_conf;
-                unsigned int i_next_rate, i_next_bit_rate;
-                unsigned int i_next_frame_length, i_next_max_frame_size;
-                unsigned int i_next_layer;
 
                 /* Build frame header */
                 i_header = GetDWBE(p_header);
 
-                i_next_frame_size = SyncInfo( i_header,
-                                              &i_next_channels,
-                                              &i_next_channels_conf,
-                                              &i_next_stereo_mode,
-                                              &i_next_rate,
-                                              &i_next_bit_rate,
-                                              &i_next_frame_length,
-                                              &i_next_max_frame_size,
-                                              &i_next_layer );
-
-                /* Free bitrate only */
-                if( p_sys->i_bit_rate == 0 && i_next_frame_size == -1 )
+                struct mpga_frameheader_s nextheader;
+                if(mpga_decode_frameheader( i_header, &nextheader ))
                 {
-                    if( (unsigned int)p_sys->i_frame_size >
-                        p_sys->i_max_frame_size )
+                    /* Free bitrate only */
+                    if( p_sys->header.i_bit_rate == 0 )
+                    {
+                        if( p_sys->header.i_frame_size > p_sys->header.i_max_frame_size )
+                        {
+                            msg_Dbg( p_dec, "frame too big %u > %u "
+                                     "(emulated startcode ?)",
+                                     p_sys->header.i_frame_size,
+                                     p_sys->header.i_max_frame_size );
+                            block_SkipByte( &p_sys->bytestream );
+                            p_sys->i_state = STATE_NOSYNC;
+                            p_sys->i_free_frame_size = MPGA_HEADER_SIZE;
+                        }
+                        else
+                        {
+                            p_sys->header.i_frame_size++;
+                        }
+                    }
+                    else
                     {
-                        msg_Dbg( p_dec, "frame too big %d > %d "
-                                 "(emulated startcode ?)", p_sys->i_frame_size,
-                                 p_sys->i_max_frame_size );
+                        msg_Dbg( p_dec, "emulated startcode on next frame" );
                         block_SkipByte( &p_sys->bytestream );
                         p_sys->i_state = STATE_NOSYNC;
-                        p_sys->i_free_frame_size = MPGA_HEADER_SIZE;
-                        break;
                     }
-
-                    p_sys->i_frame_size++;
-                    break;
-                }
-
-                if( i_next_frame_size == -1 )
-                {
-                    msg_Dbg( p_dec, "emulated startcode on next frame" );
-                    block_SkipByte( &p_sys->bytestream );
-                    p_sys->i_state = STATE_NOSYNC;
                     break;
                 }
 
                 /* Check info is in sync with previous one */
-                if( i_next_channels_conf != p_sys->i_channels_conf ||
-                    i_next_stereo_mode != p_sys->i_chan_mode ||
-                    i_next_rate != p_sys->i_rate ||
-                    i_next_layer != p_sys->i_layer ||
-                    i_next_frame_length != p_sys->i_frame_length )
+                if( nextheader.i_channels_conf != p_sys->header.i_channels_conf ||
+                    nextheader.i_chan_mode != p_sys->header.i_chan_mode ||
+                    nextheader.i_sample_rate != p_sys->header.i_sample_rate ||
+                    nextheader.i_layer != p_sys->header.i_layer ||
+                    nextheader.i_samples_per_frame != p_sys->header.i_samples_per_frame )
                 {
                     /* Free bitrate only */
-                    if( p_sys->i_bit_rate == 0 )
+                    if( p_sys->header.i_bit_rate == 0 )
                     {
-                        p_sys->i_frame_size++;
+                        p_sys->header.i_frame_size++;
                         break;
                     }
 
@@ -366,11 +343,11 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 }
 
                 /* Free bitrate only */
-                if( p_sys->i_bit_rate == 0 )
+                if( p_sys->header.i_bit_rate == 0 )
                 {
-                    if( i_next_bit_rate != 0 )
+                    if( nextheader.i_bit_rate != 0 )
                     {
-                        p_sys->i_frame_size++;
+                        p_sys->header.i_frame_size++;
                         break;
                     }
                 }
@@ -379,21 +356,21 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             else
             {
                 /* Free bitrate only */
-                if( p_sys->i_bit_rate == 0 )
+                if( p_sys->header.i_bit_rate == 0 )
                 {
-                    if( (unsigned int)p_sys->i_frame_size >
-                        p_sys->i_max_frame_size )
+                    if( p_sys->header.i_frame_size > p_sys->header.i_max_frame_size )
                     {
-                        msg_Dbg( p_dec, "frame too big %d > %d "
-                                 "(emulated startcode ?)", p_sys->i_frame_size,
-                                 p_sys->i_max_frame_size );
+                        msg_Dbg( p_dec, "frame too big %u > %u "
+                                 "(emulated startcode ?)",
+                                 p_sys->header.i_frame_size,
+                                 p_sys->header.i_max_frame_size );
                         block_SkipByte( &p_sys->bytestream );
                         p_sys->i_state = STATE_NOSYNC;
                         p_sys->i_free_frame_size = MPGA_HEADER_SIZE;
                         break;
                     }
 
-                    p_sys->i_frame_size++;
+                    p_sys->header.i_frame_size++;
                     break;
                 }
 
@@ -411,7 +388,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             /* Make sure we have enough data.
              * (Not useful if we went through NEXT_SYNC) */
             if( block_WaitBytes( &p_sys->bytestream,
-                                 p_sys->i_frame_size ) != VLC_SUCCESS )
+                                 p_sys->header.i_frame_size ) != VLC_SUCCESS )
             {
                 /* Need more data */
                 return NULL;
@@ -426,14 +403,16 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             }
 
             /* Free bitrate only */
-            if( p_sys->i_bit_rate == 0 )
+            if( p_sys->header.i_bit_rate == 0 )
             {
-                p_sys->i_free_frame_size = p_sys->i_frame_size;
+                p_sys->i_free_frame_size = p_sys->header.i_frame_size;
             }
 
             /* Copy the whole frame into the buffer. */
-            if (block_GetBytes( &p_sys->bytestream,
-                            p_buf, __MIN( (unsigned)p_sys->i_frame_size, p_out_buffer->i_buffer ) )) {
+            if ( block_GetBytes( &p_sys->bytestream, p_buf,
+                                 __MIN( p_sys->header.i_frame_size,
+                                        p_out_buffer->i_buffer ) ) )
+            {
                 block_Release(p_out_buffer);
                 return NULL;
             }
@@ -502,11 +481,8 @@ static int Open( vlc_object_t *p_this )
     block_BytestreamInit( &p_sys->bytestream );
     p_sys->i_pts = VLC_TICK_INVALID;
     p_sys->b_discontinuity = false;
-    p_sys->i_frame_size = 0;
 
-    p_sys->i_channels_conf = p_sys->i_chan_mode = p_sys->i_channels =
-    p_sys->i_rate = p_sys->i_max_frame_size = p_sys->i_frame_length =
-    p_sys->i_layer = p_sys->i_bit_rate = 0;
+    memset(&p_sys->header, 0, sizeof(p_sys->header));
 
     /* Set output properties */
     p_dec->fmt_out.i_codec = VLC_CODEC_MPGA;


=====================================
modules/packetizer/mpegaudio.h
=====================================
@@ -2,6 +2,7 @@
  * mpegaudio.h:
  *****************************************************************************
  * Copyright (C) 2001-2016 VLC authors and VideoLAN
+ *               2022 VideoLabs
  *
  * Authors: Laurent Aimar <fenrir at via.ecp.fr>
  *          Eric Petit <titer at videolan.org>
@@ -26,19 +27,26 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+struct mpga_frameheader_s
+{
+    uint8_t i_layer;
+    uint8_t i_channels;
+    uint16_t i_channels_conf;
+    uint16_t i_chan_mode;
+    uint16_t i_bit_rate;
+    uint16_t i_sample_rate;
+    uint16_t i_samples_per_frame;
+    unsigned int i_frame_size;
+    unsigned int i_max_frame_size;
+};
+
 /*****************************************************************************
- * SyncInfo: parse MPEG audio sync info
+ * mpgaDecodeFrameHeader: parse MPEG audio sync info
+ * returns 0 on success, -1 on failure
  *****************************************************************************/
-static int SyncInfo(uint32_t i_header, unsigned int *restrict pi_channels,
-                    unsigned int *restrict pi_channels_conf,
-                    unsigned int *restrict pi_chan_mode,
-                    unsigned int *restrict pi_sample_rate,
-                    unsigned int *restrict pi_bit_rate,
-                    unsigned int *restrict pi_frame_length,
-                    unsigned int *restrict pi_max_frame_size,
-                    unsigned int *restrict pi_layer)
+static int mpga_decode_frameheader(uint32_t i_header, struct mpga_frameheader_s *h)
 {
-    static const unsigned short ppi_bitrate[2][3][16] =
+    static const uint16_t ppi_bitrate[2][3][16] =
     {
         {
             /* v1 l1 */
@@ -65,29 +73,27 @@ static int SyncInfo(uint32_t i_header, unsigned int *restrict pi_channels,
         }
     };
 
-    static const unsigned short ppi_samplerate[2][4] = /* version 1 then 2 */
+    static const uint16_t ppi_samplerate[2][4] = /* version 1 then 2 */
     {
         { 44100, 48000, 32000, 0 },
         { 22050, 24000, 16000, 0 }
     };
 
-    int i_frame_size;
-
     bool b_mpeg_2_5 = 1 - ((i_header & 0x100000) >> 20);
-    int i_version = 1 - ((i_header & 0x80000) >> 19);
-    *pi_layer   = 4 - ((i_header & 0x60000) >> 17);
+    unsigned i_version_index = 1 - ((i_header & 0x80000) >> 19);
+    h->i_layer   = 4 - ((i_header & 0x60000) >> 17);
     //bool b_crc = !((i_header >> 16) & 0x01);
-    int i_bitrate_index = (i_header & 0xf000) >> 12;
-    int i_samplerate_index = (i_header & 0xc00) >> 10;
+    unsigned i_bitrate_index = (i_header & 0xf000) >> 12;
+    unsigned i_samplerate_index = (i_header & 0xc00) >> 10;
     bool b_padding = (i_header & 0x200) >> 9;
     /* Extension */
-    int i_mode = (i_header & 0xc0) >> 6;
+    uint8_t i_mode = (i_header & 0xc0) >> 6;
     /* Modeext, copyright & original */
-    int i_emphasis = i_header & 0x3;
+    uint8_t i_emphasis = i_header & 0x3;
 
-    *pi_chan_mode = 0;
+    h->i_chan_mode = 0;
 
-    if (*pi_layer == 4
+    if (h->i_layer == 4
      || i_bitrate_index == 0x0f
      || i_samplerate_index == 0x03
      || i_emphasis == 0x02)
@@ -96,48 +102,48 @@ static int SyncInfo(uint32_t i_header, unsigned int *restrict pi_channels,
     switch (i_mode)
     {
         case 2: /* dual-mono */
-            *pi_chan_mode = AOUT_CHANMODE_DUALMONO;
+            h->i_chan_mode = AOUT_CHANMODE_DUALMONO;
             /* fall through */
         case 0: /* stereo */
         case 1: /* joint stereo */
-            *pi_channels = 2;
-            *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+            h->i_channels = 2;
+            h->i_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
             break;
         case 3: /* mono */
-            *pi_channels = 1;
-            *pi_channels_conf = AOUT_CHAN_CENTER;
+            h->i_channels = 1;
+            h->i_channels_conf = AOUT_CHAN_CENTER;
             break;
     }
 
-    int i_max_bit_rate = ppi_bitrate[i_version][*pi_layer-1][14];
-    *pi_bit_rate = ppi_bitrate[i_version][*pi_layer-1][i_bitrate_index];
-    *pi_sample_rate = ppi_samplerate[i_version][i_samplerate_index];
+    uint16_t i_max_bit_rate = ppi_bitrate[i_version_index][h->i_layer-1][14];
+    h->i_bit_rate = ppi_bitrate[i_version_index][h->i_layer-1][i_bitrate_index];
+    h->i_sample_rate = ppi_samplerate[i_version_index][i_samplerate_index];
 
     if (b_mpeg_2_5)
-        *pi_sample_rate /= 2;
+        h->i_sample_rate /= 2;
 
-    switch (*pi_layer)
+    switch (h->i_layer)
     {
         case 1:
-            i_frame_size = (12000 * *pi_bit_rate / *pi_sample_rate +
+            h->i_frame_size = (12000 * h->i_bit_rate / h->i_sample_rate +
                             b_padding) * 4;
-            *pi_max_frame_size = (12000 * i_max_bit_rate /
-                                  *pi_sample_rate + 1) * 4;
-            *pi_frame_length = 384;
+            h->i_max_frame_size = (12000 * i_max_bit_rate /
+                                  h->i_sample_rate + 1) * 4;
+            h->i_samples_per_frame = 384;
             break;
 
         case 2:
-            i_frame_size = 144000 * *pi_bit_rate / *pi_sample_rate + b_padding;
-            *pi_max_frame_size = 144000 * i_max_bit_rate / *pi_sample_rate + 1;
-            *pi_frame_length = 1152;
+            h->i_frame_size = 144000 * h->i_bit_rate / h->i_sample_rate + b_padding;
+            h->i_max_frame_size = 144000 * i_max_bit_rate / h->i_sample_rate + 1;
+            h->i_samples_per_frame = 1152;
             break;
 
         case 3:
-            i_frame_size = (i_version ? 72000 : 144000) *
-                            *pi_bit_rate / *pi_sample_rate + b_padding;
-            *pi_max_frame_size = (i_version ? 72000 : 144000) *
-                                  i_max_bit_rate / *pi_sample_rate + 1;
-            *pi_frame_length = i_version ? 576 : 1152;
+            h->i_frame_size = (i_version_index ? 72000 : 144000) *
+                            h->i_bit_rate / h->i_sample_rate + b_padding;
+            h->i_max_frame_size = (i_version_index ? 72000 : 144000) *
+                                  i_max_bit_rate / h->i_sample_rate + 1;
+            h->i_samples_per_frame = i_version_index ? 576 : 1152;
             break;
 
         default:
@@ -145,8 +151,8 @@ static int SyncInfo(uint32_t i_header, unsigned int *restrict pi_channels,
     }
 
     /* Free bitrate mode can support higher bitrates */
-    if (*pi_bit_rate == 0)
-        *pi_max_frame_size *= 2;
+    if (h->i_bit_rate == 0)
+        h->i_max_frame_size *= 2;
 
-    return i_frame_size;
+    return 0;
 }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/cbbd548c6529a50ca8738dcff118cabd7dd133e7...9dafb994caf9e3a21a0afa34e68bf3f13130ab5a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/cbbd548c6529a50ca8738dcff118cabd7dd133e7...9dafb994caf9e3a21a0afa34e68bf3f13130ab5a
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list