0,0 → 1,240 |
/* |
* IEC 61937 demuxer |
* Copyright (c) 2010 Anssi Hannula <anssi.hannula at iki.fi> |
* |
* 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 |
*/ |
|
/** |
* @file |
* IEC 61937 demuxer, used for compressed data in S/PDIF |
* @author Anssi Hannula |
*/ |
|
#include "avformat.h" |
#include "spdif.h" |
#include "libavcodec/ac3.h" |
#include "libavcodec/aacadtsdec.h" |
|
static int spdif_get_offset_and_codec(AVFormatContext *s, |
enum IEC61937DataType data_type, |
const char *buf, int *offset, |
enum AVCodecID *codec) |
{ |
AACADTSHeaderInfo aac_hdr; |
GetBitContext gbc; |
|
switch (data_type & 0xff) { |
case IEC61937_AC3: |
*offset = AC3_FRAME_SIZE << 2; |
*codec = AV_CODEC_ID_AC3; |
break; |
case IEC61937_MPEG1_LAYER1: |
*offset = spdif_mpeg_pkt_offset[1][0]; |
*codec = AV_CODEC_ID_MP1; |
break; |
case IEC61937_MPEG1_LAYER23: |
*offset = spdif_mpeg_pkt_offset[1][0]; |
*codec = AV_CODEC_ID_MP3; |
break; |
case IEC61937_MPEG2_EXT: |
*offset = 4608; |
*codec = AV_CODEC_ID_MP3; |
break; |
case IEC61937_MPEG2_AAC: |
init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8); |
if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) { |
if (s) /* be silent during a probe */ |
av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n"); |
return AVERROR_INVALIDDATA; |
} |
*offset = aac_hdr.samples << 2; |
*codec = AV_CODEC_ID_AAC; |
break; |
case IEC61937_MPEG2_LAYER1_LSF: |
*offset = spdif_mpeg_pkt_offset[0][0]; |
*codec = AV_CODEC_ID_MP1; |
break; |
case IEC61937_MPEG2_LAYER2_LSF: |
*offset = spdif_mpeg_pkt_offset[0][1]; |
*codec = AV_CODEC_ID_MP2; |
break; |
case IEC61937_MPEG2_LAYER3_LSF: |
*offset = spdif_mpeg_pkt_offset[0][2]; |
*codec = AV_CODEC_ID_MP3; |
break; |
case IEC61937_DTS1: |
*offset = 2048; |
*codec = AV_CODEC_ID_DTS; |
break; |
case IEC61937_DTS2: |
*offset = 4096; |
*codec = AV_CODEC_ID_DTS; |
break; |
case IEC61937_DTS3: |
*offset = 8192; |
*codec = AV_CODEC_ID_DTS; |
break; |
default: |
if (s) { /* be silent during a probe */ |
avpriv_request_sample(s, "Data type 0x%04x in IEC 61937", |
data_type); |
} |
return AVERROR_PATCHWELCOME; |
} |
return 0; |
} |
|
/* Largest offset between bursts we currently handle, i.e. AAC with |
aac_hdr.samples = 4096 */ |
#define SPDIF_MAX_OFFSET 16384 |
|
static int spdif_probe(AVProbeData *p) |
{ |
enum AVCodecID codec; |
return ff_spdif_probe (p->buf, p->buf_size, &codec); |
} |
|
int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec) |
{ |
const uint8_t *buf = p_buf; |
const uint8_t *probe_end = p_buf + FFMIN(2 * SPDIF_MAX_OFFSET, buf_size - 1); |
const uint8_t *expected_code = buf + 7; |
uint32_t state = 0; |
int sync_codes = 0; |
int consecutive_codes = 0; |
int offset; |
|
for (; buf < probe_end; buf++) { |
state = (state << 8) | *buf; |
|
if (state == (AV_BSWAP16C(SYNCWORD1) << 16 | AV_BSWAP16C(SYNCWORD2)) |
&& buf[1] < 0x37) { |
sync_codes++; |
|
if (buf == expected_code) { |
if (++consecutive_codes >= 2) |
return AVPROBE_SCORE_MAX; |
} else |
consecutive_codes = 0; |
|
if (buf + 4 + AAC_ADTS_HEADER_SIZE > p_buf + buf_size) |
break; |
|
/* continue probing to find more sync codes */ |
probe_end = FFMIN(buf + SPDIF_MAX_OFFSET, p_buf + buf_size - 1); |
|
/* skip directly to the next sync code */ |
if (!spdif_get_offset_and_codec(NULL, (buf[2] << 8) | buf[1], |
&buf[5], &offset, codec)) { |
if (buf + offset >= p_buf + buf_size) |
break; |
expected_code = buf + offset; |
buf = expected_code - 7; |
} |
} |
} |
|
if (!sync_codes) |
return 0; |
|
if (sync_codes >= 6) |
/* good amount of sync codes but with unexpected offsets */ |
return AVPROBE_SCORE_EXTENSION; |
|
/* some sync codes were found */ |
return AVPROBE_SCORE_EXTENSION / 4; |
} |
|
static int spdif_read_header(AVFormatContext *s) |
{ |
s->ctx_flags |= AVFMTCTX_NOHEADER; |
return 0; |
} |
|
int ff_spdif_read_packet(AVFormatContext *s, AVPacket *pkt) |
{ |
AVIOContext *pb = s->pb; |
enum IEC61937DataType data_type; |
enum AVCodecID codec_id; |
uint32_t state = 0; |
int pkt_size_bits, offset, ret; |
|
while (state != (AV_BSWAP16C(SYNCWORD1) << 16 | AV_BSWAP16C(SYNCWORD2))) { |
state = (state << 8) | avio_r8(pb); |
if (avio_feof(pb)) |
return AVERROR_EOF; |
} |
|
data_type = avio_rl16(pb); |
pkt_size_bits = avio_rl16(pb); |
|
if (pkt_size_bits % 16) |
avpriv_request_sample(s, "Packet not ending at a 16-bit boundary"); |
|
ret = av_new_packet(pkt, FFALIGN(pkt_size_bits, 16) >> 3); |
if (ret) |
return ret; |
|
pkt->pos = avio_tell(pb) - BURST_HEADER_SIZE; |
|
if (avio_read(pb, pkt->data, pkt->size) < pkt->size) { |
av_free_packet(pkt); |
return AVERROR_EOF; |
} |
ff_spdif_bswap_buf16((uint16_t *)pkt->data, (uint16_t *)pkt->data, pkt->size >> 1); |
|
ret = spdif_get_offset_and_codec(s, data_type, pkt->data, |
&offset, &codec_id); |
if (ret) { |
av_free_packet(pkt); |
return ret; |
} |
|
/* skip over the padding to the beginning of the next frame */ |
avio_skip(pb, offset - pkt->size - BURST_HEADER_SIZE); |
|
if (!s->nb_streams) { |
/* first packet, create a stream */ |
AVStream *st = avformat_new_stream(s, NULL); |
if (!st) { |
av_free_packet(pkt); |
return AVERROR(ENOMEM); |
} |
st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
st->codec->codec_id = codec_id; |
} else if (codec_id != s->streams[0]->codec->codec_id) { |
avpriv_report_missing_feature(s, "Codec change in IEC 61937"); |
return AVERROR_PATCHWELCOME; |
} |
|
if (!s->bit_rate && s->streams[0]->codec->sample_rate) |
/* stream bitrate matches 16-bit stereo PCM bitrate for currently |
supported codecs */ |
s->bit_rate = 2 * 16 * s->streams[0]->codec->sample_rate; |
|
return 0; |
} |
|
AVInputFormat ff_spdif_demuxer = { |
.name = "spdif", |
.long_name = NULL_IF_CONFIG_SMALL("IEC 61937 (compressed data in S/PDIF)"), |
.read_probe = spdif_probe, |
.read_header = spdif_read_header, |
.read_packet = ff_spdif_read_packet, |
.flags = AVFMT_GENERIC_INDEX, |
}; |