| /* |
| * 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 CodecID *codec) |
| { |
| AACADTSHeaderInfo aac_hdr; |
| GetBitContext gbc; |
| |
| switch (data_type & 0xff) { |
| case IEC61937_AC3: |
| *offset = AC3_FRAME_SIZE << 2; |
| *codec = CODEC_ID_AC3; |
| break; |
| case IEC61937_MPEG1_LAYER1: |
| *offset = spdif_mpeg_pkt_offset[1][0]; |
| *codec = CODEC_ID_MP1; |
| break; |
| case IEC61937_MPEG1_LAYER23: |
| *offset = spdif_mpeg_pkt_offset[1][0]; |
| *codec = CODEC_ID_MP3; |
| break; |
| case IEC61937_MPEG2_EXT: |
| *offset = 4608; |
| *codec = CODEC_ID_MP3; |
| break; |
| case IEC61937_MPEG2_AAC: |
| init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8); |
| if (ff_aac_parse_header(&gbc, &aac_hdr)) { |
| 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 = CODEC_ID_AAC; |
| break; |
| case IEC61937_MPEG2_LAYER1_LSF: |
| *offset = spdif_mpeg_pkt_offset[0][0]; |
| *codec = CODEC_ID_MP1; |
| break; |
| case IEC61937_MPEG2_LAYER2_LSF: |
| *offset = spdif_mpeg_pkt_offset[0][1]; |
| *codec = CODEC_ID_MP2; |
| break; |
| case IEC61937_MPEG2_LAYER3_LSF: |
| *offset = spdif_mpeg_pkt_offset[0][2]; |
| *codec = CODEC_ID_MP3; |
| break; |
| case IEC61937_DTS1: |
| *offset = 2048; |
| *codec = CODEC_ID_DTS; |
| break; |
| case IEC61937_DTS2: |
| *offset = 4096; |
| *codec = CODEC_ID_DTS; |
| break; |
| case IEC61937_DTS3: |
| *offset = 8192; |
| *codec = CODEC_ID_DTS; |
| break; |
| default: |
| if (s) { /* be silent during a probe */ |
| av_log(s, AV_LOG_WARNING, "Data type 0x%04x", data_type); |
| av_log_missing_feature(s, " in IEC 61937 is", 1); |
| } |
| 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) |
| { |
| const uint8_t *buf = p->buf; |
| const uint8_t *probe_end = p->buf + FFMIN(2 * SPDIF_MAX_OFFSET, p->buf_size - 1); |
| const uint8_t *expected_code = buf + 7; |
| uint32_t state = 0; |
| int sync_codes = 0; |
| int consecutive_codes = 0; |
| int offset; |
| enum CodecID codec; |
| |
| 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 + p->buf_size) |
| break; |
| |
| /* continue probing to find more sync codes */ |
| probe_end = FFMIN(buf + SPDIF_MAX_OFFSET, p->buf + p->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 + p->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_MAX / 2; |
| |
| /* some sync codes were found */ |
| return AVPROBE_SCORE_MAX / 8; |
| } |
| |
| static int spdif_read_header(AVFormatContext *s, AVFormatParameters *ap) |
| { |
| s->ctx_flags |= AVFMTCTX_NOHEADER; |
| return 0; |
| } |
| |
| static int spdif_read_packet(AVFormatContext *s, AVPacket *pkt) |
| { |
| AVIOContext *pb = s->pb; |
| enum IEC61937DataType data_type; |
| enum CodecID 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 (url_feof(pb)) |
| return AVERROR_EOF; |
| } |
| |
| data_type = avio_rl16(pb); |
| pkt_size_bits = avio_rl16(pb); |
| |
| if (pkt_size_bits % 16) |
| av_log_ask_for_sample(s, "Packet does not end to 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 = av_new_stream(s, 0); |
| 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) { |
| av_log_missing_feature(s, "codec change in IEC 61937", 0); |
| 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 = { |
| "spdif", |
| NULL_IF_CONFIG_SMALL("IEC 61937 (compressed data in S/PDIF)"), |
| 0, |
| spdif_probe, |
| spdif_read_header, |
| spdif_read_packet, |
| .flags = AVFMT_GENERIC_INDEX, |
| }; |