1/* 2 * AIX demuxer 3 * Copyright (c) 2016 Paul B Mahol 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/intreadwrite.h" 23#include "avformat.h" 24#include "demux.h" 25#include "internal.h" 26 27static int aix_probe(const AVProbeData *p) 28{ 29 if (AV_RL32(p->buf) != MKTAG('A','I','X','F') || 30 AV_RB32(p->buf + 8) != 0x01000014 || 31 AV_RB32(p->buf + 12) != 0x00000800) 32 return 0; 33 34 return AVPROBE_SCORE_MAX; 35} 36 37static int aix_read_header(AVFormatContext *s) 38{ 39 unsigned nb_streams, first_offset, nb_segments; 40 unsigned stream_list_offset; 41 unsigned segment_list_offset = 0x20; 42 unsigned segment_list_entry_size = 0x10; 43 unsigned size; 44 int i; 45 46 avio_skip(s->pb, 4); 47 first_offset = avio_rb32(s->pb) + 8; 48 avio_skip(s->pb, 16); 49 nb_segments = avio_rb16(s->pb); 50 if (nb_segments == 0) 51 return AVERROR_INVALIDDATA; 52 stream_list_offset = segment_list_offset + segment_list_entry_size * nb_segments + 0x10; 53 if (stream_list_offset >= first_offset) 54 return AVERROR_INVALIDDATA; 55 avio_seek(s->pb, stream_list_offset, SEEK_SET); 56 nb_streams = avio_r8(s->pb); 57 if (nb_streams == 0) 58 return AVERROR_INVALIDDATA; 59 avio_skip(s->pb, 7); 60 for (i = 0; i < nb_streams; i++) { 61 AVStream *st = avformat_new_stream(s, NULL); 62 63 if (!st) 64 return AVERROR(ENOMEM); 65 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 66 st->codecpar->codec_id = AV_CODEC_ID_ADPCM_ADX; 67 st->codecpar->sample_rate = avio_rb32(s->pb); 68 st->codecpar->ch_layout.nb_channels = avio_r8(s->pb); 69 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); 70 avio_skip(s->pb, 3); 71 } 72 73 avio_seek(s->pb, first_offset, SEEK_SET); 74 for (i = 0; i < nb_streams; i++) { 75 if (avio_rl32(s->pb) != MKTAG('A','I','X','P')) 76 return AVERROR_INVALIDDATA; 77 size = avio_rb32(s->pb); 78 if (size <= 8) 79 return AVERROR_INVALIDDATA; 80 avio_skip(s->pb, 8); 81 ff_get_extradata(s, s->streams[i]->codecpar, s->pb, size - 8); 82 } 83 84 return 0; 85} 86 87static int aix_read_packet(AVFormatContext *s, AVPacket *pkt) 88{ 89 unsigned size, index, duration, chunk; 90 int64_t pos; 91 int sequence, ret, i; 92 93 pos = avio_tell(s->pb); 94 if (avio_feof(s->pb)) 95 return AVERROR_EOF; 96 chunk = avio_rl32(s->pb); 97 size = avio_rb32(s->pb); 98 if (chunk == MKTAG('A','I','X','E')) { 99 avio_skip(s->pb, size); 100 for (i = 0; i < s->nb_streams; i++) { 101 if (avio_feof(s->pb)) 102 return AVERROR_EOF; 103 chunk = avio_rl32(s->pb); 104 size = avio_rb32(s->pb); 105 avio_skip(s->pb, size); 106 } 107 pos = avio_tell(s->pb); 108 chunk = avio_rl32(s->pb); 109 size = avio_rb32(s->pb); 110 } 111 112 if (chunk != MKTAG('A','I','X','P')) 113 return AVERROR_INVALIDDATA; 114 if (size <= 8) 115 return AVERROR_INVALIDDATA; 116 index = avio_r8(s->pb); 117 if (avio_r8(s->pb) != s->nb_streams || index >= s->nb_streams) 118 return AVERROR_INVALIDDATA; 119 duration = avio_rb16(s->pb); 120 sequence = avio_rb32(s->pb); 121 if (sequence < 0) { 122 avio_skip(s->pb, size - 8); 123 return 0; 124 } 125 126 ret = av_get_packet(s->pb, pkt, size - 8); 127 pkt->stream_index = index; 128 pkt->duration = duration; 129 pkt->pos = pos; 130 return ret; 131} 132 133const AVInputFormat ff_aix_demuxer = { 134 .name = "aix", 135 .long_name = NULL_IF_CONFIG_SMALL("CRI AIX"), 136 .read_probe = aix_probe, 137 .read_header = aix_read_header, 138 .read_packet = aix_read_packet, 139 .extensions = "aix", 140 .flags = AVFMT_GENERIC_INDEX, 141}; 142