[FFmpeg-devel] [PATCH 3/4] avformat/pp_bnk: treat music files are stereo

Andreas Rheinhardt andreas.rheinhardt at gmail.com
Tue Mar 16 08:39:43 EET 2021


Zane van Iperen:
> These files are technically a series of planar mono tracks.
> If the "music" flag is set, merge the packets from the two
> mono tracks, essentially replicating:
> 
>   [0:a:0][0:a:1]join=inputs=2:channel_layout=stereo[a]
> 
> Signed-off-by: Zane van Iperen <zane at zanevaniperen.com>
> ---
>  libavformat/pp_bnk.c | 60 ++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 50 insertions(+), 10 deletions(-)
> 
> diff --git a/libavformat/pp_bnk.c b/libavformat/pp_bnk.c
> index 8364de1fd9..970ef09923 100644
> --- a/libavformat/pp_bnk.c
> +++ b/libavformat/pp_bnk.c
> @@ -55,6 +55,8 @@ typedef struct PPBnkCtx {
>      int             track_count;
>      PPBnkCtxTrack   *tracks;
>      uint32_t        current_track;
> +    int             is_music;
> +    AVPacket        pkt;
>  } PPBnkCtx;
>  
>  enum {
> @@ -194,8 +196,12 @@ static int pp_bnk_read_header(AVFormatContext *s)
>          goto fail;
>      }
>  
> +    ctx->is_music = (hdr.flags & PP_BNK_FLAG_MUSIC) &&
> +                    (ctx->track_count == 2) &&
> +                    (ctx->tracks[0].data_size == ctx->tracks[1].data_size);
> +
>      /* Build the streams. */
> -    for (int i = 0; i < ctx->track_count; i++) {
> +    for (int i = 0; i < (ctx->is_music ? 1 : ctx->track_count); i++) {
>          if (!(st = avformat_new_stream(s, NULL))) {
>              ret = AVERROR(ENOMEM);
>              goto fail;
> @@ -204,14 +210,21 @@ static int pp_bnk_read_header(AVFormatContext *s)
>          par                         = st->codecpar;
>          par->codec_type             = AVMEDIA_TYPE_AUDIO;
>          par->codec_id               = AV_CODEC_ID_ADPCM_IMA_CUNNING;
> -        par->format                 = AV_SAMPLE_FMT_S16;
> -        par->channel_layout         = AV_CH_LAYOUT_MONO;
> -        par->channels               = 1;
> +        par->format                 = AV_SAMPLE_FMT_S16P;
> +
> +        if (ctx->is_music) {
> +            par->channel_layout         = AV_CH_LAYOUT_STEREO;
> +            par->channels               = 2;
> +        } else {
> +            par->channel_layout         = AV_CH_LAYOUT_MONO;
> +            par->channels               = 1;
> +        }
> +
>          par->sample_rate            = hdr.sample_rate;
>          par->bits_per_coded_sample  = 4;
>          par->bits_per_raw_sample    = 16;
>          par->block_align            = 1;
> -        par->bit_rate               = par->sample_rate * par->bits_per_coded_sample;
> +        par->bit_rate               = par->sample_rate * par->bits_per_coded_sample * par->channels;
>  
>          avpriv_set_pts_info(st, 64, 1, par->sample_rate);
>          st->start_time              = 0;
> @@ -253,7 +266,22 @@ static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt)
>  
>          size = FFMIN(trk->data_size - trk->bytes_read, PP_BNK_MAX_READ_SIZE);
>  
> -        if ((ret = av_get_packet(s->pb, pkt, size)) == AVERROR_EOF) {
> +        if (!ctx->is_music)
> +            ret = av_new_packet(&ctx->pkt, size);
> +        else if (ctx->current_track == 0)
> +            ret = av_new_packet(&ctx->pkt, size * 2);
> +        else
> +            ret = 0;
> +
> +        if (ret < 0)
> +            return ret;
> +
> +        if (ctx->is_music)
> +            ret = avio_read(s->pb, ctx->pkt.data + size * ctx->current_track, size);
> +        else
> +            ret = avio_read(s->pb, ctx->pkt.data, size);
> +
> +        if (ret == AVERROR_EOF) {
>              /* If we've hit EOF, don't attempt this track again. */
>              trk->data_size = trk->bytes_read;
>              continue;
> @@ -261,10 +289,21 @@ static int pp_bnk_read_packet(AVFormatContext *s, AVPacket *pkt)
>              return ret;
>          }
>  
> -        trk->bytes_read    += ret;
> -        pkt->flags         &= ~AV_PKT_FLAG_CORRUPT;
> -        pkt->stream_index   = ctx->current_track++;
> -        pkt->duration       = ret * 2;
> +        trk->bytes_read        += ret;
> +        ctx->pkt.flags         &= ~AV_PKT_FLAG_CORRUPT;
> +        ctx->pkt.stream_index   = ctx->current_track++;
> +        ctx->pkt.duration       = ret * 2;
> +
> +        if (ctx->is_music) {
> +            if (ctx->pkt.stream_index == 0)
> +                return FFERROR_REDO;

Wouldn't a simple continue have the same effect? This would allow to
avoid the temporary packet.

> +
> +            ctx->pkt.stream_index = 0;
> +        } else {
> +            ctx->pkt.size = ret;
> +        }
> +
> +        av_packet_move_ref(pkt, &ctx->pkt);
>          return 0;
>      }
>  
> @@ -277,6 +316,7 @@ static int pp_bnk_read_close(AVFormatContext *s)
>      PPBnkCtx *ctx = s->priv_data;
>  
>      av_freep(&ctx->tracks);
> +    av_packet_unref(&ctx->pkt);
>  
>      return 0;
>  }
> 



More information about the ffmpeg-devel mailing list