Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6147 | serge | 1 | /* |
2 | * mtv demuxer |
||
3 | * Copyright (c) 2006 Reynaldo H. Verdejo Pinochet |
||
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 | /** |
||
23 | * @file |
||
24 | * MTV demuxer. |
||
25 | */ |
||
26 | |||
27 | #include "libavutil/bswap.h" |
||
28 | #include "libavutil/intreadwrite.h" |
||
29 | #include "avformat.h" |
||
30 | #include "internal.h" |
||
31 | |||
32 | #define MTV_ASUBCHUNK_DATA_SIZE 500 |
||
33 | #define MTV_HEADER_SIZE 512 |
||
34 | #define MTV_AUDIO_PADDING_SIZE 12 |
||
35 | #define MTV_IMAGE_DEFAULT_BPP 16 |
||
36 | #define MTV_AUDIO_SAMPLING_RATE 44100 |
||
37 | |||
38 | typedef struct MTVDemuxContext { |
||
39 | |||
40 | unsigned int file_size; ///< filesize, not always right |
||
41 | unsigned int segments; ///< number of 512 byte segments |
||
42 | unsigned int audio_identifier; ///< 'MP3' on all files I have seen |
||
43 | unsigned int audio_br; ///< bitrate of audio channel (mp3) |
||
44 | unsigned int img_colorfmt; ///< frame colorfmt rgb 565/555 |
||
45 | unsigned int img_bpp; ///< frame bits per pixel |
||
46 | unsigned int img_width; |
||
47 | unsigned int img_height; |
||
48 | unsigned int img_segment_size; ///< size of image segment |
||
49 | unsigned int video_fps; |
||
50 | unsigned int full_segment_size; |
||
51 | |||
52 | } MTVDemuxContext; |
||
53 | |||
54 | static int mtv_probe(AVProbeData *p) |
||
55 | { |
||
56 | /* we need at least 57 bytes from the header |
||
57 | * to try parsing all required fields |
||
58 | */ |
||
59 | if (p->buf_size < 57) |
||
60 | return 0; |
||
61 | |||
62 | /* Magic is 'AMV' */ |
||
63 | if (*p->buf != 'A' || *(p->buf + 1) != 'M' || *(p->buf + 2) != 'V') |
||
64 | return 0; |
||
65 | |||
66 | /* Audio magic is always MP3 */ |
||
67 | if (p->buf[43] != 'M' || p->buf[44] != 'P' || p->buf[45] != '3') |
||
68 | return 0; |
||
69 | |||
70 | /* Check for nonzero in bpp and (width|height) header fields */ |
||
71 | if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54]))) |
||
72 | return 0; |
||
73 | |||
74 | /* If width or height are 0 then imagesize header field should not */ |
||
75 | if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54])) |
||
76 | { |
||
77 | if(!!AV_RL16(&p->buf[56])) |
||
78 | return AVPROBE_SCORE_EXTENSION; |
||
79 | else |
||
80 | return 0; |
||
81 | } |
||
82 | |||
83 | /* Image bpp is not an absolutely required |
||
84 | * field as we latter claim it should be 16 |
||
85 | * no matter what. All samples in the wild |
||
86 | * are RGB565/555. |
||
87 | */ |
||
88 | if(p->buf[51] != MTV_IMAGE_DEFAULT_BPP) |
||
89 | return AVPROBE_SCORE_EXTENSION / 2; |
||
90 | |||
91 | /* We had enough data to parse header values |
||
92 | * but we expect to be able to get 512 bytes |
||
93 | * of header to be sure. |
||
94 | */ |
||
95 | if (p->buf_size < MTV_HEADER_SIZE) |
||
96 | return AVPROBE_SCORE_EXTENSION; |
||
97 | |||
98 | return AVPROBE_SCORE_MAX; |
||
99 | } |
||
100 | |||
101 | static int mtv_read_header(AVFormatContext *s) |
||
102 | { |
||
103 | MTVDemuxContext *mtv = s->priv_data; |
||
104 | AVIOContext *pb = s->pb; |
||
105 | AVStream *st; |
||
106 | unsigned int audio_subsegments; |
||
107 | |||
108 | avio_skip(pb, 3); |
||
109 | mtv->file_size = avio_rl32(pb); |
||
110 | mtv->segments = avio_rl32(pb); |
||
111 | avio_skip(pb, 32); |
||
112 | mtv->audio_identifier = avio_rl24(pb); |
||
113 | mtv->audio_br = avio_rl16(pb); |
||
114 | mtv->img_colorfmt = avio_rl24(pb); |
||
115 | mtv->img_bpp = avio_r8(pb); |
||
116 | mtv->img_width = avio_rl16(pb); |
||
117 | mtv->img_height = avio_rl16(pb); |
||
118 | mtv->img_segment_size = avio_rl16(pb); |
||
119 | |||
120 | /* Assume 16bpp even if claimed otherwise. |
||
121 | * We know its going to be RGBG565/555 anyway |
||
122 | */ |
||
123 | if (mtv->img_bpp != MTV_IMAGE_DEFAULT_BPP) { |
||
124 | av_log (s, AV_LOG_WARNING, "Header claims %dbpp (!= 16). Ignoring\n", |
||
125 | mtv->img_bpp); |
||
126 | mtv->img_bpp = MTV_IMAGE_DEFAULT_BPP; |
||
127 | } |
||
128 | |||
129 | /* Calculate width and height if missing from header */ |
||
130 | |||
131 | if (!mtv->img_width && mtv->img_height > 0 && mtv->img_bpp >= 8) |
||
132 | mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3) |
||
133 | / mtv->img_height; |
||
134 | |||
135 | if (!mtv->img_height && mtv->img_width > 0 && mtv->img_bpp >= 8) |
||
136 | mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3) |
||
137 | / mtv->img_width; |
||
138 | |||
139 | if(!mtv->img_height || !mtv->img_width || !mtv->img_segment_size){ |
||
140 | av_log(s, AV_LOG_ERROR, "width or height or segment_size is invalid and I cannot calculate them from other information\n"); |
||
141 | return AVERROR_INVALIDDATA; |
||
142 | } |
||
143 | |||
144 | avio_skip(pb, 4); |
||
145 | audio_subsegments = avio_rl16(pb); |
||
146 | |||
147 | if (audio_subsegments == 0) { |
||
148 | avpriv_request_sample(s, "MTV files without audio"); |
||
149 | return AVERROR_PATCHWELCOME; |
||
150 | } |
||
151 | |||
152 | mtv->full_segment_size = |
||
153 | audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) + |
||
154 | mtv->img_segment_size; |
||
155 | mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments; |
||
156 | |||
157 | // FIXME Add sanity check here |
||
158 | |||
159 | // all systems go! init decoders |
||
160 | |||
161 | // video - raw rgb565 |
||
162 | |||
163 | st = avformat_new_stream(s, NULL); |
||
164 | if(!st) |
||
165 | return AVERROR(ENOMEM); |
||
166 | |||
167 | avpriv_set_pts_info(st, 64, 1, mtv->video_fps); |
||
168 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
||
169 | st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; |
||
170 | st->codec->pix_fmt = AV_PIX_FMT_RGB565BE; |
||
171 | st->codec->width = mtv->img_width; |
||
172 | st->codec->height = mtv->img_height; |
||
173 | st->codec->extradata = av_strdup("BottomUp"); |
||
174 | st->codec->extradata_size = 9; |
||
175 | |||
176 | // audio - mp3 |
||
177 | |||
178 | st = avformat_new_stream(s, NULL); |
||
179 | if(!st) |
||
180 | return AVERROR(ENOMEM); |
||
181 | |||
182 | avpriv_set_pts_info(st, 64, 1, MTV_AUDIO_SAMPLING_RATE); |
||
183 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
||
184 | st->codec->codec_id = AV_CODEC_ID_MP3; |
||
185 | st->codec->bit_rate = mtv->audio_br; |
||
186 | st->need_parsing = AVSTREAM_PARSE_FULL; |
||
187 | |||
188 | // Jump over header |
||
189 | |||
190 | if(avio_seek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE) |
||
191 | return AVERROR(EIO); |
||
192 | |||
193 | return 0; |
||
194 | |||
195 | } |
||
196 | |||
197 | static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) |
||
198 | { |
||
199 | MTVDemuxContext *mtv = s->priv_data; |
||
200 | AVIOContext *pb = s->pb; |
||
201 | int ret; |
||
202 | |||
203 | if((avio_tell(pb) - s->internal->data_offset + mtv->img_segment_size) % mtv->full_segment_size) |
||
204 | { |
||
205 | avio_skip(pb, MTV_AUDIO_PADDING_SIZE); |
||
206 | |||
207 | ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE); |
||
208 | if(ret < 0) |
||
209 | return ret; |
||
210 | |||
211 | pkt->pos -= MTV_AUDIO_PADDING_SIZE; |
||
212 | pkt->stream_index = 1; |
||
213 | |||
214 | }else |
||
215 | { |
||
216 | ret = av_get_packet(pb, pkt, mtv->img_segment_size); |
||
217 | if(ret < 0) |
||
218 | return ret; |
||
219 | |||
220 | pkt->stream_index = 0; |
||
221 | } |
||
222 | |||
223 | return ret; |
||
224 | } |
||
225 | |||
226 | AVInputFormat ff_mtv_demuxer = { |
||
227 | .name = "mtv", |
||
228 | .long_name = NULL_IF_CONFIG_SMALL("MTV"), |
||
229 | .priv_data_size = sizeof(MTVDemuxContext), |
||
230 | .read_probe = mtv_probe, |
||
231 | .read_header = mtv_read_header, |
||
232 | .read_packet = mtv_read_packet, |
||
233 | };>>>>>>>>>>> |