1/* 2 * RedSpark demuxer 3 * Copyright (c) 2013 James Almer 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 "libavcodec/bytestream.h" 23#include "libavutil/intreadwrite.h" 24#include "avformat.h" 25#include "avio.h" 26#include "internal.h" 27 28#define HEADER_SIZE 4096 29#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 30 31typedef struct RedSparkContext { 32 int samples_count; 33} RedSparkContext; 34 35static int redspark_probe(const AVProbeData *p) 36{ 37 uint32_t key, data; 38 uint8_t header[8]; 39 40 /* Decrypt first 8 bytes of the header */ 41 data = AV_RB32(p->buf); 42 key = data ^ 0x52656453; 43 data ^= key; 44 AV_WB32(header, data); 45 key = rol(key, 11); 46 47 key += rol(key, 3); 48 data = AV_RB32(p->buf + 4) ^ key; 49 AV_WB32(header + 4, data); 50 51 if (AV_RB64(header) == AV_RB64("RedSpark")) 52 return AVPROBE_SCORE_MAX; 53 54 return 0; 55} 56 57static int redspark_read_header(AVFormatContext *s) 58{ 59 AVIOContext *pb = s->pb; 60 RedSparkContext *redspark = s->priv_data; 61 AVCodecParameters *par; 62 GetByteContext gbc; 63 int i, coef_off, ret = 0; 64 uint32_t key, data; 65 uint8_t header[HEADER_SIZE]; 66 AVStream *st; 67 68 st = avformat_new_stream(s, NULL); 69 if (!st) 70 return AVERROR(ENOMEM); 71 par = st->codecpar; 72 73 /* Decrypt header */ 74 data = avio_rb32(pb); 75 key = data ^ 0x52656453; 76 data ^= key; 77 AV_WB32(header, data); 78 key = rol(key, 11); 79 80 for (i = 4; i < HEADER_SIZE; i += 4) { 81 key += rol(key, 3); 82 data = avio_rb32(pb) ^ key; 83 AV_WB32(header + i, data); 84 } 85 86 par->codec_id = AV_CODEC_ID_ADPCM_THP; 87 par->codec_type = AVMEDIA_TYPE_AUDIO; 88 89 bytestream2_init(&gbc, header, HEADER_SIZE); 90 bytestream2_seek(&gbc, 0x3c, SEEK_SET); 91 par->sample_rate = bytestream2_get_be32u(&gbc); 92 if (par->sample_rate <= 0 || par->sample_rate > 96000) { 93 av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", par->sample_rate); 94 return AVERROR_INVALIDDATA; 95 } 96 97 st->duration = bytestream2_get_be32u(&gbc) * 14; 98 redspark->samples_count = 0; 99 bytestream2_skipu(&gbc, 10); 100 par->ch_layout.nb_channels = bytestream2_get_byteu(&gbc); 101 if (!par->ch_layout.nb_channels) { 102 return AVERROR_INVALIDDATA; 103 } 104 105 coef_off = 0x54 + par->ch_layout.nb_channels * 8; 106 if (bytestream2_get_byteu(&gbc)) // Loop flag 107 coef_off += 16; 108 109 if (coef_off + par->ch_layout.nb_channels * (32 + 14) > HEADER_SIZE) { 110 return AVERROR_INVALIDDATA; 111 } 112 113 if (ff_alloc_extradata(par, 32 * par->ch_layout.nb_channels)) { 114 return AVERROR_INVALIDDATA; 115 } 116 117 /* Get the ADPCM table */ 118 bytestream2_seek(&gbc, coef_off, SEEK_SET); 119 for (i = 0; i < par->ch_layout.nb_channels; i++) { 120 if (bytestream2_get_bufferu(&gbc, par->extradata + i * 32, 32) != 32) { 121 return AVERROR_INVALIDDATA; 122 } 123 bytestream2_skipu(&gbc, 14); 124 } 125 126 avpriv_set_pts_info(st, 64, 1, par->sample_rate); 127 128 return ret; 129} 130 131static int redspark_read_packet(AVFormatContext *s, AVPacket *pkt) 132{ 133 AVCodecParameters *par = s->streams[0]->codecpar; 134 RedSparkContext *redspark = s->priv_data; 135 uint32_t size = 8 * par->ch_layout.nb_channels; 136 int ret; 137 138 if (avio_feof(s->pb) || redspark->samples_count == s->streams[0]->duration) 139 return AVERROR_EOF; 140 141 ret = av_get_packet(s->pb, pkt, size); 142 if (ret != size) { 143 return AVERROR(EIO); 144 } 145 146 pkt->duration = 14; 147 redspark->samples_count += pkt->duration; 148 pkt->stream_index = 0; 149 150 return ret; 151} 152 153const AVInputFormat ff_redspark_demuxer = { 154 .name = "redspark", 155 .long_name = NULL_IF_CONFIG_SMALL("RedSpark"), 156 .priv_data_size = sizeof(RedSparkContext), 157 .read_probe = redspark_probe, 158 .read_header = redspark_read_header, 159 .read_packet = redspark_read_packet, 160 .extensions = "rsd", 161}; 162