3 * Copyright (c) 2006 Reynaldo H. Verdejo Pinochet
5 * This file is part of FFmpeg.
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.
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.
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
27 #include "libavutil/bswap.h"
28 #include "libavutil/intreadwrite.h"
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
38 typedef struct MTVDemuxContext
{
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
;
54 static int mtv_probe(AVProbeData
*p
)
56 /* we need at least 57 bytes from the header
57 * to try parsing all required fields
63 if (*p
->buf
!= 'A' || *(p
->buf
+ 1) != 'M' || *(p
->buf
+ 2) != 'V')
66 /* Audio magic is always MP3 */
67 if (p
->buf
[43] != 'M' || p
->buf
[44] != 'P' || p
->buf
[45] != '3')
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])))
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]))
77 if(!!AV_RL16(&p
->buf
[56]))
78 return AVPROBE_SCORE_EXTENSION
;
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
88 if(p
->buf
[51] != MTV_IMAGE_DEFAULT_BPP
)
89 return AVPROBE_SCORE_EXTENSION
/ 2;
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.
95 if (p
->buf_size
< MTV_HEADER_SIZE
)
96 return AVPROBE_SCORE_EXTENSION
;
98 return AVPROBE_SCORE_MAX
;
101 static int mtv_read_header(AVFormatContext
*s
)
103 MTVDemuxContext
*mtv
= s
->priv_data
;
104 AVIOContext
*pb
= s
->pb
;
106 unsigned int audio_subsegments
;
109 mtv
->file_size
= avio_rl32(pb
);
110 mtv
->segments
= avio_rl32(pb
);
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
);
120 /* Assume 16bpp even if claimed otherwise.
121 * We know its going to be RGBG565/555 anyway
123 if (mtv
->img_bpp
!= MTV_IMAGE_DEFAULT_BPP
) {
124 av_log (s
, AV_LOG_WARNING
, "Header claims %dbpp (!= 16). Ignoring\n",
126 mtv
->img_bpp
= MTV_IMAGE_DEFAULT_BPP
;
129 /* Calculate width and height if missing from header */
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)
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)
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
;
145 audio_subsegments
= avio_rl16(pb
);
147 if (audio_subsegments
== 0) {
148 avpriv_request_sample(s
, "MTV files without audio");
149 return AVERROR_PATCHWELCOME
;
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
;
157 // FIXME Add sanity check here
159 // all systems go! init decoders
161 // video - raw rgb565
163 st
= avformat_new_stream(s
, NULL
);
165 return AVERROR(ENOMEM
);
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;
178 st
= avformat_new_stream(s
, NULL
);
180 return AVERROR(ENOMEM
);
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
;
190 if(avio_seek(pb
, MTV_HEADER_SIZE
, SEEK_SET
) != MTV_HEADER_SIZE
)
197 static int mtv_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
199 MTVDemuxContext
*mtv
= s
->priv_data
;
200 AVIOContext
*pb
= s
->pb
;
203 if((avio_tell(pb
) - s
->data_offset
+ mtv
->img_segment_size
) % mtv
->full_segment_size
)
205 avio_skip(pb
, MTV_AUDIO_PADDING_SIZE
);
207 ret
= av_get_packet(pb
, pkt
, MTV_ASUBCHUNK_DATA_SIZE
);
211 pkt
->pos
-= MTV_AUDIO_PADDING_SIZE
;
212 pkt
->stream_index
= 1;
216 ret
= av_get_packet(pb
, pkt
, mtv
->img_segment_size
);
220 pkt
->stream_index
= 0;
226 AVInputFormat ff_mtv_demuxer
= {
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
,