00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/bswap.h"
00028 #include "libavutil/intreadwrite.h"
00029 #include "avformat.h"
00030 #include "internal.h"
00031
00032 #define MTV_ASUBCHUNK_DATA_SIZE 500
00033 #define MTV_HEADER_SIZE 512
00034 #define MTV_AUDIO_PADDING_SIZE 12
00035 #define AUDIO_SAMPLING_RATE 44100
00036
00037 typedef struct MTVDemuxContext {
00038
00039 unsigned int file_size;
00040 unsigned int segments;
00041 unsigned int audio_identifier;
00042 unsigned int audio_br;
00043 unsigned int img_colorfmt;
00044 unsigned int img_bpp;
00045 unsigned int img_width;
00046 unsigned int img_height;
00047 unsigned int img_segment_size;
00048 unsigned int video_fps;
00049 unsigned int full_segment_size;
00050
00051 } MTVDemuxContext;
00052
00053 static int mtv_probe(AVProbeData *p)
00054 {
00055
00056 if (*p->buf != 'A' || *(p->buf + 1) != 'M' || *(p->buf + 2) != 'V')
00057 return 0;
00058
00059
00060 if(p->buf_size < 57 || !(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
00061 return 0;
00062
00063
00064 if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54]))
00065 {
00066 if(!!AV_RL16(&p->buf[56]))
00067 return AVPROBE_SCORE_MAX/2;
00068 else
00069 return 0;
00070 }
00071
00072 if(p->buf[51] != 16)
00073 return AVPROBE_SCORE_MAX/4;
00074
00075 return AVPROBE_SCORE_MAX;
00076 }
00077
00078 static int mtv_read_header(AVFormatContext *s)
00079 {
00080 MTVDemuxContext *mtv = s->priv_data;
00081 AVIOContext *pb = s->pb;
00082 AVStream *st;
00083 unsigned int audio_subsegments;
00084
00085 avio_skip(pb, 3);
00086 mtv->file_size = avio_rl32(pb);
00087 mtv->segments = avio_rl32(pb);
00088 avio_skip(pb, 32);
00089 mtv->audio_identifier = avio_rl24(pb);
00090 mtv->audio_br = avio_rl16(pb);
00091 mtv->img_colorfmt = avio_rl24(pb);
00092 mtv->img_bpp = avio_r8(pb);
00093 mtv->img_width = avio_rl16(pb);
00094 mtv->img_height = avio_rl16(pb);
00095 mtv->img_segment_size = avio_rl16(pb);
00096
00097
00098
00099 if(mtv->img_bpp>>3){
00100 if(!mtv->img_width && mtv->img_height)
00101 mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
00102 / mtv->img_height;
00103
00104 if(!mtv->img_height && mtv->img_width)
00105 mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
00106 / mtv->img_width;
00107 }
00108 if(!mtv->img_height || !mtv->img_width){
00109 av_log(s, AV_LOG_ERROR, "width or height is invalid and I cannot calculate them from other information\n");
00110 return AVERROR(EINVAL);
00111 }
00112
00113 avio_skip(pb, 4);
00114 audio_subsegments = avio_rl16(pb);
00115
00116 if (audio_subsegments == 0) {
00117 av_log_ask_for_sample(s, "MTV files without audio are not supported\n");
00118 return AVERROR_INVALIDDATA;
00119 }
00120
00121 mtv->full_segment_size =
00122 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) +
00123 mtv->img_segment_size;
00124 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments;
00125
00126
00127
00128
00129
00130
00131
00132 st = avformat_new_stream(s, NULL);
00133 if(!st)
00134 return AVERROR(ENOMEM);
00135
00136 avpriv_set_pts_info(st, 64, 1, mtv->video_fps);
00137 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00138 st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
00139 st->codec->pix_fmt = AV_PIX_FMT_RGB565BE;
00140 st->codec->width = mtv->img_width;
00141 st->codec->height = mtv->img_height;
00142 st->codec->sample_rate = mtv->video_fps;
00143 st->codec->extradata = av_strdup("BottomUp");
00144 st->codec->extradata_size = 9;
00145
00146
00147
00148 st = avformat_new_stream(s, NULL);
00149 if(!st)
00150 return AVERROR(ENOMEM);
00151
00152 avpriv_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
00153 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00154 st->codec->codec_id = AV_CODEC_ID_MP3;
00155 st->codec->bit_rate = mtv->audio_br;
00156 st->need_parsing = AVSTREAM_PARSE_FULL;
00157
00158
00159
00160 if(avio_seek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE)
00161 return AVERROR(EIO);
00162
00163 return 0;
00164
00165 }
00166
00167 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt)
00168 {
00169 MTVDemuxContext *mtv = s->priv_data;
00170 AVIOContext *pb = s->pb;
00171 int ret;
00172
00173 if((avio_tell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size)
00174 {
00175 avio_skip(pb, MTV_AUDIO_PADDING_SIZE);
00176
00177 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE);
00178 if(ret < 0)
00179 return ret;
00180
00181 pkt->pos -= MTV_AUDIO_PADDING_SIZE;
00182 pkt->stream_index = 1;
00183
00184 }else
00185 {
00186 ret = av_get_packet(pb, pkt, mtv->img_segment_size);
00187 if(ret < 0)
00188 return ret;
00189
00190 pkt->stream_index = 0;
00191 }
00192
00193 return ret;
00194 }
00195
00196 AVInputFormat ff_mtv_demuxer = {
00197 .name = "mtv",
00198 .long_name = NULL_IF_CONFIG_SMALL("MTV"),
00199 .priv_data_size = sizeof(MTVDemuxContext),
00200 .read_probe = mtv_probe,
00201 .read_header = mtv_read_header,
00202 .read_packet = mtv_read_packet,
00203 };