Files
FFmpeg/libavformat/msf.c
T
Kacper Michajłow 72dac5d5c0 avformat/msf: compute the packet size in read_header
The packet size was derived from the codecpar channel count on every
read. For MP3, which is parsed, the channel count of the parser's codec
context is copied back to codecpar, 0 when the decoder could not be
opened, and the empty packets that followed never reached EOF, so
seek_frame_generic() looped forever.

Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
2026-10-29 18:28:42 +00:00

123 lines
4.3 KiB
C

/*
* MSF demuxer
* Copyright (c) 2015 Paul B Mahol
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "demux.h"
#include "internal.h"
typedef struct MSFDemuxContext {
int packet_size;
} MSFDemuxContext;
static int msf_probe(const AVProbeData *p)
{
if (memcmp(p->buf, "MSF", 3))
return 0;
if (AV_RB32(p->buf+8) <= 0)
return 0;
if (AV_RB32(p->buf+16) <= 0)
return 0;
if (AV_RB32(p->buf+4) > 16)
return AVPROBE_SCORE_MAX / 5; //unsupported / unknown codec
return AVPROBE_SCORE_MAX / 3 * 2;
}
static int msf_read_header(AVFormatContext *s)
{
MSFDemuxContext *msf = s->priv_data;
unsigned codec, size;
AVStream *st;
int ret;
avio_skip(s->pb, 4);
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
codec = avio_rb32(s->pb);
st->codecpar->ch_layout.nb_channels = avio_rb32(s->pb);
if (st->codecpar->ch_layout.nb_channels <= 0 ||
st->codecpar->ch_layout.nb_channels >= INT_MAX / 1024)
return AVERROR_INVALIDDATA;
size = avio_rb32(s->pb);
st->codecpar->sample_rate = avio_rb32(s->pb);
if (st->codecpar->sample_rate <= 0)
return AVERROR_INVALIDDATA;
// avio_rb32(s->pb); /* byte flags with encoder info */
switch (codec) {
case 0: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE; break;
case 1: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break;
case 3: st->codecpar->block_align = 16 * st->codecpar->ch_layout.nb_channels;
st->codecpar->codec_id = AV_CODEC_ID_ADPCM_PSX; break;
case 4:
case 5:
case 6: st->codecpar->block_align = (codec == 4 ? 96 : codec == 5 ? 152 : 192) * st->codecpar->ch_layout.nb_channels;
if (st->codecpar->ch_layout.nb_channels > UINT16_MAX / 2048)
return AVERROR_INVALIDDATA;
ret = ff_alloc_extradata(st->codecpar, 14);
if (ret < 0)
return ret;
memset(st->codecpar->extradata, 0, st->codecpar->extradata_size);
AV_WL16(st->codecpar->extradata, 1); /* version */
AV_WL16(st->codecpar->extradata+2, 2048 * st->codecpar->ch_layout.nb_channels); /* unknown size */
AV_WL16(st->codecpar->extradata+6, codec == 4 ? 1 : 0); /* joint stereo */
AV_WL16(st->codecpar->extradata+8, codec == 4 ? 1 : 0); /* joint stereo (repeat?) */
AV_WL16(st->codecpar->extradata+10, 1);
st->codecpar->codec_id = AV_CODEC_ID_ATRAC3; break;
case 7: ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
st->codecpar->codec_id = AV_CODEC_ID_MP3; break;
default:
avpriv_request_sample(s, "Codec %d", codec);
return AVERROR_PATCHWELCOME;
}
msf->packet_size = st->codecpar->block_align ? st->codecpar->block_align
: 1024 * st->codecpar->ch_layout.nb_channels;
st->duration = av_get_audio_frame_duration2(st->codecpar, size);
avio_skip(s->pb, 0x40 - avio_tell(s->pb));
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
return 0;
}
static int msf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MSFDemuxContext *msf = s->priv_data;
return av_get_packet(s->pb, pkt, msf->packet_size);
}
const FFInputFormat ff_msf_demuxer = {
.p.name = "msf",
.p.long_name = NULL_IF_CONFIG_SMALL("Sony PS3 MSF"),
.p.extensions = "msf",
.priv_data_size = sizeof(MSFDemuxContext),
.read_probe = msf_probe,
.read_header = msf_read_header,
.read_packet = msf_read_packet,
};