Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * RSD 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
static const AVCodecTag rsd_tags[] = {
29
    { AV_CODEC_ID_ADPCM_THP,       MKTAG('G','A','D','P') },
30
    { AV_CODEC_ID_ADPCM_IMA_RAD,   MKTAG('R','A','D','P') },
31
    { AV_CODEC_ID_PCM_S16BE,       MKTAG('P','C','M','B') },
32
    { AV_CODEC_ID_PCM_S16LE,       MKTAG('P','C','M',' ') },
33
    { AV_CODEC_ID_NONE, 0 },
34
};
35
 
36
static const uint32_t rsd_unsupported_tags[] = {
37
    MKTAG('O','G','G',' '),
38
    MKTAG('V','A','G',' '),
39
    MKTAG('W','A','D','P'),
40
    MKTAG('X','A','D','P'),
41
    MKTAG('X','M','A',' '),
42
};
43
 
44
static int rsd_probe(AVProbeData *p)
45
{
46
    if (!memcmp(p->buf, "RSD", 3) &&
47
        p->buf[3] - '0' >= 2 && p->buf[3] - '0' <= 6)
48
        return AVPROBE_SCORE_EXTENSION;
49
    return 0;
50
}
51
 
52
static int rsd_read_header(AVFormatContext *s)
53
{
54
    AVIOContext *pb = s->pb;
55
    int i, version, start = 0x800;
56
    AVCodecContext *codec;
57
    AVStream *st = avformat_new_stream(s, NULL);
58
 
59
    if (!st)
60
        return AVERROR(ENOMEM);
61
 
62
    avio_skip(pb, 3); // "RSD"
63
    version = avio_r8(pb) - '0';
64
 
65
    codec = st->codec;
66
    codec->codec_type = AVMEDIA_TYPE_AUDIO;
67
    codec->codec_tag  = avio_rl32(pb);
68
    codec->codec_id   = ff_codec_get_id(rsd_tags, codec->codec_tag);
69
    if (!codec->codec_id) {
70
        char tag_buf[5];
71
 
72
        av_get_codec_tag_string(tag_buf, sizeof(tag_buf), codec->codec_tag);
73
        for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) {
74
            if (codec->codec_tag == rsd_unsupported_tags[i]) {
75
                avpriv_request_sample(s, "Codec tag: %s", tag_buf);
76
                return AVERROR_PATCHWELCOME;
77
            }
78
        }
79
        av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf);
80
        return AVERROR_INVALIDDATA;
81
    }
82
 
83
    codec->channels = avio_rl32(pb);
84
    if (!codec->channels)
85
        return AVERROR_INVALIDDATA;
86
 
87
    avio_skip(pb, 4); // Bit depth
88
    codec->sample_rate = avio_rl32(pb);
89
    if (!codec->sample_rate)
90
        return AVERROR_INVALIDDATA;
91
 
92
    avio_skip(pb, 4); // Unknown
93
 
94
    switch (codec->codec_id) {
95
    case AV_CODEC_ID_ADPCM_IMA_RAD:
96
        codec->block_align = 20 * codec->channels;
97
        if (pb->seekable)
98
            st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
99
        break;
100
    case AV_CODEC_ID_ADPCM_THP:
101
        /* RSD3GADP is mono, so only alloc enough memory
102
           to store the coeff table for a single channel. */
103
 
104
        if (ff_alloc_extradata(codec, 32))
105
            return AVERROR(ENOMEM);
106
 
107
        start = avio_rl32(pb);
108
 
109
        if (avio_read(s->pb, codec->extradata, 32) != 32)
110
            return AVERROR_INVALIDDATA;
111
 
112
        for (i = 0; i < 16; i++)
113
            AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2));
114
 
115
        if (pb->seekable)
116
            st->duration = (avio_size(pb) - start) / 8 * 14;
117
        break;
118
    case AV_CODEC_ID_PCM_S16LE:
119
    case AV_CODEC_ID_PCM_S16BE:
120
        if (version != 4)
121
            start = avio_rl32(pb);
122
 
123
        if (pb->seekable)
124
            st->duration = (avio_size(pb) - start) / 2 / codec->channels;
125
        break;
126
    }
127
 
128
    avio_skip(pb, start - avio_tell(pb));
129
 
130
    avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
131
 
132
    return 0;
133
}
134
 
135
static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
136
{
137
    AVCodecContext *codec = s->streams[0]->codec;
138
    int ret, size = 1024;
139
 
140
    if (url_feof(s->pb))
141
        return AVERROR_EOF;
142
 
143
    if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD)
144
        ret = av_get_packet(s->pb, pkt, codec->block_align);
145
    else
146
        ret = av_get_packet(s->pb, pkt, size);
147
 
148
    if (ret != size) {
149
        if (ret < 0) {
150
            av_free_packet(pkt);
151
            return ret;
152
        }
153
        av_shrink_packet(pkt, ret);
154
    }
155
    pkt->stream_index = 0;
156
 
157
    return ret;
158
}
159
 
160
AVInputFormat ff_rsd_demuxer = {
161
    .name           =   "rsd",
162
    .long_name      =   NULL_IF_CONFIG_SMALL("GameCube RSD"),
163
    .read_probe     =   rsd_probe,
164
    .read_header    =   rsd_read_header,
165
    .read_packet    =   rsd_read_packet,
166
    .extensions     =   "rsd",
167
    .codec_tag      =   (const AVCodecTag* const []){rsd_tags, 0},
168
};