Go to the documentation of this file.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[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, AVFormatParameters *ap)
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_width)
00100 mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
00101 / mtv->img_height;
00102
00103 if(!mtv->img_height)
00104 mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
00105 / mtv->img_width;
00106
00107 avio_skip(pb, 4);
00108 audio_subsegments = avio_rl16(pb);
00109
00110 if (audio_subsegments == 0) {
00111 av_log_ask_for_sample(s, "MTV files without audio are not supported\n");
00112 return AVERROR_INVALIDDATA;
00113 }
00114
00115 mtv->full_segment_size =
00116 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) +
00117 mtv->img_segment_size;
00118 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments;
00119
00120
00121
00122
00123
00124
00125
00126 st = avformat_new_stream(s, NULL);
00127 if(!st)
00128 return AVERROR(ENOMEM);
00129
00130 avpriv_set_pts_info(st, 64, 1, mtv->video_fps);
00131 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00132 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00133 st->codec->pix_fmt = PIX_FMT_RGB565;
00134 st->codec->width = mtv->img_width;
00135 st->codec->height = mtv->img_height;
00136 st->codec->sample_rate = mtv->video_fps;
00137 st->codec->extradata = av_strdup("BottomUp");
00138 st->codec->extradata_size = 9;
00139
00140
00141
00142 st = avformat_new_stream(s, NULL);
00143 if(!st)
00144 return AVERROR(ENOMEM);
00145
00146 avpriv_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
00147 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00148 st->codec->codec_id = CODEC_ID_MP3;
00149 st->codec->bit_rate = mtv->audio_br;
00150 st->need_parsing = AVSTREAM_PARSE_FULL;
00151
00152
00153
00154 if(avio_seek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE)
00155 return AVERROR(EIO);
00156
00157 return 0;
00158
00159 }
00160
00161 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt)
00162 {
00163 MTVDemuxContext *mtv = s->priv_data;
00164 AVIOContext *pb = s->pb;
00165 int ret;
00166 #if !HAVE_BIGENDIAN
00167 int i;
00168 #endif
00169
00170 if((avio_tell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size)
00171 {
00172 avio_skip(pb, MTV_AUDIO_PADDING_SIZE);
00173
00174 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE);
00175 if(ret < 0)
00176 return ret;
00177
00178 pkt->pos -= MTV_AUDIO_PADDING_SIZE;
00179 pkt->stream_index = 1;
00180
00181 }else
00182 {
00183 ret = av_get_packet(pb, pkt, mtv->img_segment_size);
00184 if(ret < 0)
00185 return ret;
00186
00187 #if !HAVE_BIGENDIAN
00188
00189
00190
00191
00192
00193
00194
00195 for(i=0;i<mtv->img_segment_size/2;i++)
00196 *((uint16_t *)pkt->data+i) = av_bswap16(*((uint16_t *)pkt->data+i));
00197 #endif
00198 pkt->stream_index = 0;
00199 }
00200
00201 return ret;
00202 }
00203
00204 AVInputFormat ff_mtv_demuxer = {
00205 .name = "MTV",
00206 .long_name = NULL_IF_CONFIG_SMALL("MTV format"),
00207 .priv_data_size = sizeof(MTVDemuxContext),
00208 .read_probe = mtv_probe,
00209 .read_header = mtv_read_header,
00210 .read_packet = mtv_read_packet,
00211 };