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
00031 #define MTV_ASUBCHUNK_DATA_SIZE 500
00032 #define MTV_HEADER_SIZE 512
00033 #define MTV_AUDIO_PADDING_SIZE 12
00034 #define AUDIO_SAMPLING_RATE 44100
00035 #define VIDEO_SID 0
00036 #define AUDIO_SID 1
00037
00038 typedef struct MTVDemuxContext {
00039
00040 unsigned int file_size;
00041 unsigned int segments;
00042 unsigned int audio_identifier;
00043 unsigned int audio_br;
00044 unsigned int img_colorfmt;
00045 unsigned int img_bpp;
00046 unsigned int img_width;
00047 unsigned int img_height;
00048 unsigned int img_segment_size;
00049 unsigned int video_fps;
00050 unsigned int full_segment_size;
00051
00052 } MTVDemuxContext;
00053
00054 static int mtv_probe(AVProbeData *p)
00055 {
00056
00057 if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V')
00058 return 0;
00059
00060
00061 if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
00062 return 0;
00063
00064
00065 if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54]))
00066 {
00067 if(!!AV_RL16(&p->buf[56]))
00068 return AVPROBE_SCORE_MAX/2;
00069 else
00070 return 0;
00071 }
00072
00073 if(p->buf[51] != 16)
00074 return AVPROBE_SCORE_MAX/4;
00075
00076 return AVPROBE_SCORE_MAX;
00077 }
00078
00079 static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00080 {
00081 MTVDemuxContext *mtv = s->priv_data;
00082 ByteIOContext *pb = s->pb;
00083 AVStream *st;
00084 unsigned int audio_subsegments;
00085
00086 url_fskip(pb, 3);
00087 mtv->file_size = get_le32(pb);
00088 mtv->segments = get_le32(pb);
00089 url_fskip(pb, 32);
00090 mtv->audio_identifier = get_le24(pb);
00091 mtv->audio_br = get_le16(pb);
00092 mtv->img_colorfmt = get_le24(pb);
00093 mtv->img_bpp = get_byte(pb);
00094 mtv->img_width = get_le16(pb);
00095 mtv->img_height = get_le16(pb);
00096 mtv->img_segment_size = get_le16(pb);
00097
00098
00099
00100 if(!mtv->img_width)
00101 mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
00102 / mtv->img_height;
00103
00104 if(!mtv->img_height)
00105 mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
00106 / mtv->img_width;
00107
00108 url_fskip(pb, 4);
00109 audio_subsegments = get_le16(pb);
00110 mtv->full_segment_size =
00111 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) +
00112 mtv->img_segment_size;
00113 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments;
00114
00115
00116
00117
00118
00119
00120
00121 st = av_new_stream(s, VIDEO_SID);
00122 if(!st)
00123 return AVERROR(ENOMEM);
00124
00125 av_set_pts_info(st, 64, 1, mtv->video_fps);
00126 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00127 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00128 st->codec->pix_fmt = PIX_FMT_RGB565;
00129 st->codec->width = mtv->img_width;
00130 st->codec->height = mtv->img_height;
00131 st->codec->sample_rate = mtv->video_fps;
00132 st->codec->extradata = av_strdup("BottomUp");
00133 st->codec->extradata_size = 9;
00134
00135
00136
00137 st = av_new_stream(s, AUDIO_SID);
00138 if(!st)
00139 return AVERROR(ENOMEM);
00140
00141 av_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
00142 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00143 st->codec->codec_id = CODEC_ID_MP3;
00144 st->codec->bit_rate = mtv->audio_br;
00145 st->need_parsing = AVSTREAM_PARSE_FULL;
00146
00147
00148
00149 if(url_fseek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE)
00150 return AVERROR(EIO);
00151
00152 return 0;
00153
00154 }
00155
00156 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt)
00157 {
00158 MTVDemuxContext *mtv = s->priv_data;
00159 ByteIOContext *pb = s->pb;
00160 int ret;
00161 #if !HAVE_BIGENDIAN
00162 int i;
00163 #endif
00164
00165 if((url_ftell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size)
00166 {
00167 url_fskip(pb, MTV_AUDIO_PADDING_SIZE);
00168
00169 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE);
00170 if(ret < 0)
00171 return ret;
00172
00173 pkt->pos -= MTV_AUDIO_PADDING_SIZE;
00174 pkt->stream_index = AUDIO_SID;
00175
00176 }else
00177 {
00178 ret = av_get_packet(pb, pkt, mtv->img_segment_size);
00179 if(ret < 0)
00180 return ret;
00181
00182 #if !HAVE_BIGENDIAN
00183
00184
00185
00186
00187
00188
00189
00190 for(i=0;i<mtv->img_segment_size/2;i++)
00191 *((uint16_t *)pkt->data+i) = bswap_16(*((uint16_t *)pkt->data+i));
00192 #endif
00193 pkt->stream_index = VIDEO_SID;
00194 }
00195
00196 return ret;
00197 }
00198
00199 AVInputFormat mtv_demuxer = {
00200 "MTV",
00201 NULL_IF_CONFIG_SMALL("MTV format"),
00202 sizeof(MTVDemuxContext),
00203 mtv_probe,
00204 mtv_read_header,
00205 mtv_read_packet,
00206 };