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