• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/xmv.c

Go to the documentation of this file.
00001 /*
00002  * Microsoft XMV demuxer
00003  * Copyright (c) 2011 Sven Hesse <drmccoy@drmccoy.de>
00004  * Copyright (c) 2011 Matthew Hoops <clone2727@gmail.com>
00005  *
00006  * This file is part of FFmpeg.
00007  *
00008  * FFmpeg is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * FFmpeg is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with FFmpeg; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00028 #include <stdint.h>
00029 
00030 #include "libavutil/intreadwrite.h"
00031 
00032 #include "avformat.h"
00033 #include "internal.h"
00034 #include "riff.h"
00035 
00037 #define XMV_MIN_HEADER_SIZE 36
00038 
00040 #define XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT 1
00041 
00042 #define XMV_AUDIO_ADPCM51_FRONTCENTERLOW 2
00043 
00044 #define XMV_AUDIO_ADPCM51_REARLEFTRIGHT  4
00045 
00047 #define XMV_AUDIO_ADPCM51 (XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT | \
00048                            XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \
00049                            XMV_AUDIO_ADPCM51_REARLEFTRIGHT)
00050 
00052 typedef struct XMVVideoPacket {
00053     int stream_index; 
00054 
00055     uint32_t data_size;   
00056     uint64_t data_offset; 
00057 
00058     uint32_t current_frame; 
00059     uint32_t frame_count;   
00060 
00061     int     has_extradata; 
00062     uint8_t extradata[4];  
00063 
00064     int64_t last_pts; 
00065     int64_t pts;      
00066 } XMVVideoPacket;
00067 
00069 typedef struct XMVAudioPacket {
00070     int stream_index; 
00071 
00072     /* Stream format properties. */
00073     uint16_t compression;     
00074     uint16_t channels;        
00075     uint32_t sample_rate;     
00076     uint16_t bits_per_sample; 
00077     uint32_t bit_rate;        
00078     uint16_t flags;           
00079     uint16_t block_align;     
00080     uint16_t block_samples;   
00081 
00082     enum CodecID codec_id; 
00083 
00084     uint32_t data_size;   
00085     uint64_t data_offset; 
00086 
00087     uint32_t frame_size; 
00088 
00089     uint64_t block_count; 
00090 } XMVAudioPacket;
00091 
00093 typedef struct XMVDemuxContext {
00094     uint16_t audio_track_count; 
00095 
00096     uint32_t this_packet_size; 
00097     uint32_t next_packet_size; 
00098 
00099     uint64_t this_packet_offset; 
00100     uint64_t next_packet_offset; 
00101 
00102     uint16_t current_stream; 
00103     uint16_t stream_count;   
00104 
00105     XMVVideoPacket  video; 
00106     XMVAudioPacket *audio; 
00107 } XMVDemuxContext;
00108 
00109 static int xmv_probe(AVProbeData *p)
00110 {
00111     uint32_t file_version;
00112 
00113     if (p->buf_size < XMV_MIN_HEADER_SIZE)
00114         return 0;
00115 
00116     file_version = AV_RL32(p->buf + 16);
00117     if ((file_version == 0) || (file_version > 4))
00118         return 0;
00119 
00120     if (!memcmp(p->buf + 12, "xobX", 4))
00121         return AVPROBE_SCORE_MAX;
00122 
00123     return 0;
00124 }
00125 
00126 static int xmv_read_header(AVFormatContext *s,
00127                            AVFormatParameters *ap)
00128 {
00129     XMVDemuxContext *xmv = s->priv_data;
00130     AVIOContext     *pb  = s->pb;
00131     AVStream        *vst = NULL;
00132 
00133     uint32_t file_version;
00134     uint32_t this_packet_size;
00135     uint16_t audio_track;
00136 
00137     avio_skip(pb, 4); /* Next packet size */
00138 
00139     this_packet_size = avio_rl32(pb);
00140 
00141     avio_skip(pb, 4); /* Max packet size */
00142     avio_skip(pb, 4); /* "xobX" */
00143 
00144     file_version = avio_rl32(pb);
00145     if ((file_version != 4) && (file_version != 2))
00146         av_log_ask_for_sample(s, "Found uncommon version %d\n", file_version);
00147 
00148 
00149     /* Video track */
00150 
00151     vst = avformat_new_stream(s, NULL);
00152     if (!vst)
00153         return AVERROR(ENOMEM);
00154 
00155     avpriv_set_pts_info(vst, 32, 1, 1000);
00156 
00157     vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00158     vst->codec->codec_id   = CODEC_ID_WMV2;
00159     vst->codec->codec_tag  = MKBETAG('W', 'M', 'V', '2');
00160     vst->codec->width      = avio_rl32(pb);
00161     vst->codec->height     = avio_rl32(pb);
00162 
00163     vst->duration          = avio_rl32(pb);
00164 
00165     xmv->video.stream_index = vst->index;
00166 
00167     /* Audio tracks */
00168 
00169     xmv->audio_track_count = avio_rl16(pb);
00170 
00171     avio_skip(pb, 2); /* Unknown (padding?) */
00172 
00173     xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket));
00174     if (!xmv->audio)
00175         return AVERROR(ENOMEM);
00176 
00177     for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
00178         XMVAudioPacket *packet = &xmv->audio[audio_track];
00179         AVStream *ast = NULL;
00180 
00181         packet->compression     = avio_rl16(pb);
00182         packet->channels        = avio_rl16(pb);
00183         packet->sample_rate     = avio_rl32(pb);
00184         packet->bits_per_sample = avio_rl16(pb);
00185         packet->flags           = avio_rl16(pb);
00186 
00187         packet->bit_rate      = packet->bits_per_sample *
00188                                 packet->sample_rate *
00189                                 packet->channels;
00190         packet->block_align   = 36 * packet->channels;
00191         packet->block_samples = 64;
00192         packet->codec_id      = ff_wav_codec_get_id(packet->compression,
00193                                                     packet->bits_per_sample);
00194 
00195         packet->stream_index = -1;
00196 
00197         packet->frame_size  = 0;
00198         packet->block_count = 0;
00199 
00200         /* TODO: ADPCM'd 5.1 sound is encoded in three separate streams.
00201          *       Those need to be interleaved to a proper 5.1 stream. */
00202         if (packet->flags & XMV_AUDIO_ADPCM51)
00203             av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream "
00204                                       "(0x%04X)\n", packet->flags);
00205 
00206         ast = avformat_new_stream(s, NULL);
00207         if (!ast)
00208             return AVERROR(ENOMEM);
00209 
00210         ast->codec->codec_type            = AVMEDIA_TYPE_AUDIO;
00211         ast->codec->codec_id              = packet->codec_id;
00212         ast->codec->codec_tag             = packet->compression;
00213         ast->codec->channels              = packet->channels;
00214         ast->codec->sample_rate           = packet->sample_rate;
00215         ast->codec->bits_per_coded_sample = packet->bits_per_sample;
00216         ast->codec->bit_rate              = packet->bit_rate;
00217         ast->codec->block_align           = 36 * packet->channels;
00218 
00219         avpriv_set_pts_info(ast, 32, packet->block_samples, packet->sample_rate);
00220 
00221         packet->stream_index = ast->index;
00222 
00223         ast->duration = vst->duration;
00224     }
00225 
00226 
00227     /* Initialize the packet context */
00228 
00229     xmv->next_packet_offset = avio_tell(pb);
00230     xmv->next_packet_size   = this_packet_size - xmv->next_packet_offset;
00231     xmv->stream_count       = xmv->audio_track_count + 1;
00232 
00233     return 0;
00234 }
00235 
00236 static void xmv_read_extradata(uint8_t *extradata, AVIOContext *pb)
00237 {
00238     /* Read the XMV extradata */
00239 
00240     uint32_t data = avio_rl32(pb);
00241 
00242     int mspel_bit        = !!(data & 0x01);
00243     int loop_filter      = !!(data & 0x02);
00244     int abt_flag         = !!(data & 0x04);
00245     int j_type_bit       = !!(data & 0x08);
00246     int top_left_mv_flag = !!(data & 0x10);
00247     int per_mb_rl_bit    = !!(data & 0x20);
00248     int slice_count      = (data >> 6) & 7;
00249 
00250     /* Write it back as standard WMV2 extradata */
00251 
00252     data = 0;
00253 
00254     data |= mspel_bit        << 15;
00255     data |= loop_filter      << 14;
00256     data |= abt_flag         << 13;
00257     data |= j_type_bit       << 12;
00258     data |= top_left_mv_flag << 11;
00259     data |= per_mb_rl_bit    << 10;
00260     data |= slice_count      <<  7;
00261 
00262     AV_WB32(extradata, data);
00263 }
00264 
00265 static int xmv_process_packet_header(AVFormatContext *s)
00266 {
00267     XMVDemuxContext *xmv = s->priv_data;
00268     AVIOContext     *pb  = s->pb;
00269 
00270     uint8_t  data[8];
00271     uint16_t audio_track;
00272     uint64_t data_offset;
00273 
00274     /* Next packet size */
00275     xmv->next_packet_size = avio_rl32(pb);
00276 
00277     /* Packet video header */
00278 
00279     if (avio_read(pb, data, 8) != 8)
00280         return AVERROR(EIO);
00281 
00282     xmv->video.data_size     = AV_RL32(data) & 0x007FFFFF;
00283 
00284     xmv->video.current_frame = 0;
00285     xmv->video.frame_count   = (AV_RL32(data) >> 23) & 0xFF;
00286 
00287     xmv->video.has_extradata = (data[3] & 0x80) != 0;
00288 
00289     /* Adding the audio data sizes and the video data size keeps you 4 bytes
00290      * short for every audio track. But as playing around with XMV files with
00291      * ADPCM audio showed, taking the extra 4 bytes from the audio data gives
00292      * you either completely distorted audio or click (when skipping the
00293      * remaining 68 bytes of the ADPCM block). Substracting 4 bytes for every
00294      * audio track from the video data works at least for the audio. Probably
00295      * some alignment thing?
00296      * The video data has (always?) lots of padding, so it should work out...
00297      */
00298     xmv->video.data_size -= xmv->audio_track_count * 4;
00299 
00300     xmv->current_stream = 0;
00301     if (!xmv->video.frame_count) {
00302         xmv->video.frame_count = 1;
00303         xmv->current_stream    = xmv->stream_count > 1;
00304     }
00305 
00306     /* Packet audio header */
00307 
00308     for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
00309         XMVAudioPacket *packet = &xmv->audio[audio_track];
00310 
00311         if (avio_read(pb, data, 4) != 4)
00312             return AVERROR(EIO);
00313 
00314         packet->data_size = AV_RL32(data) & 0x007FFFFF;
00315         if ((packet->data_size == 0) && (audio_track != 0))
00316             /* This happens when I create an XMV with several identical audio
00317              * streams. From the size calculations, duplicating the previous
00318              * stream's size works out, but the track data itself is silent.
00319              * Maybe this should also redirect the offset to the previous track?
00320              */
00321             packet->data_size = xmv->audio[audio_track - 1].data_size;
00322 
00323         /* Carve up the audio data in frame_count slices */
00324         packet->frame_size  = packet->data_size  / xmv->video.frame_count;
00325         packet->frame_size -= packet->frame_size % packet->block_align;
00326     }
00327 
00328     /* Packet data offsets */
00329 
00330     data_offset = avio_tell(pb);
00331 
00332     xmv->video.data_offset = data_offset;
00333     data_offset += xmv->video.data_size;
00334 
00335     for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
00336         xmv->audio[audio_track].data_offset = data_offset;
00337         data_offset += xmv->audio[audio_track].data_size;
00338     }
00339 
00340     /* Video frames header */
00341 
00342     /* Read new video extra data */
00343     if (xmv->video.data_size > 0) {
00344         if (xmv->video.has_extradata) {
00345             xmv_read_extradata(xmv->video.extradata, pb);
00346 
00347             xmv->video.data_size   -= 4;
00348             xmv->video.data_offset += 4;
00349 
00350             if (xmv->video.stream_index >= 0) {
00351                 AVStream *vst = s->streams[xmv->video.stream_index];
00352 
00353                 assert(xmv->video.stream_index < s->nb_streams);
00354 
00355                 if (vst->codec->extradata_size < 4) {
00356                     av_free(vst->codec->extradata);
00357 
00358                     vst->codec->extradata =
00359                         av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
00360                     vst->codec->extradata_size = 4;
00361                 }
00362 
00363                 memcpy(vst->codec->extradata, xmv->video.extradata, 4);
00364             }
00365         }
00366     }
00367 
00368     return 0;
00369 }
00370 
00371 static int xmv_fetch_new_packet(AVFormatContext *s)
00372 {
00373     XMVDemuxContext *xmv = s->priv_data;
00374     AVIOContext     *pb  = s->pb;
00375     int result;
00376 
00377     /* Seek to it */
00378     xmv->this_packet_offset = xmv->next_packet_offset;
00379     if (avio_seek(pb, xmv->this_packet_offset, SEEK_SET) != xmv->this_packet_offset)
00380         return AVERROR(EIO);
00381 
00382     /* Update the size */
00383     xmv->this_packet_size = xmv->next_packet_size;
00384     if (xmv->this_packet_size < (12 + xmv->audio_track_count * 4))
00385         return AVERROR(EIO);
00386 
00387     /* Process the header */
00388     result = xmv_process_packet_header(s);
00389     if (result)
00390         return result;
00391 
00392     /* Update the offset */
00393     xmv->next_packet_offset = xmv->this_packet_offset + xmv->this_packet_size;
00394 
00395     return 0;
00396 }
00397 
00398 static int xmv_fetch_audio_packet(AVFormatContext *s,
00399                                   AVPacket *pkt, uint32_t stream)
00400 {
00401     XMVDemuxContext *xmv   = s->priv_data;
00402     AVIOContext     *pb    = s->pb;
00403     XMVAudioPacket  *audio = &xmv->audio[stream];
00404 
00405     uint32_t data_size;
00406     uint32_t block_count;
00407     int result;
00408 
00409     /* Seek to it */
00410     if (avio_seek(pb, audio->data_offset, SEEK_SET) != audio->data_offset)
00411         return AVERROR(EIO);
00412 
00413     if ((xmv->video.current_frame + 1) < xmv->video.frame_count)
00414         /* Not the last frame, get at most frame_size bytes. */
00415         data_size = FFMIN(audio->frame_size, audio->data_size);
00416     else
00417         /* Last frame, get the rest. */
00418         data_size = audio->data_size;
00419 
00420     /* Read the packet */
00421     result = av_get_packet(pb, pkt, data_size);
00422     if (result <= 0)
00423         return result;
00424 
00425     pkt->stream_index = audio->stream_index;
00426 
00427     /* Calculate the PTS */
00428 
00429     block_count = data_size / audio->block_align;
00430 
00431     pkt->duration = block_count;
00432     pkt->pts      = audio->block_count;
00433     pkt->dts      = AV_NOPTS_VALUE;
00434 
00435     audio->block_count += block_count;
00436 
00437     /* Advance offset */
00438     audio->data_size   -= data_size;
00439     audio->data_offset += data_size;
00440 
00441     return 0;
00442 }
00443 
00444 static int xmv_fetch_video_packet(AVFormatContext *s,
00445                                   AVPacket *pkt)
00446 {
00447     XMVDemuxContext *xmv   = s->priv_data;
00448     AVIOContext     *pb    = s->pb;
00449     XMVVideoPacket  *video = &xmv->video;
00450 
00451     int result;
00452     uint32_t frame_header;
00453     uint32_t frame_size, frame_timestamp;
00454     uint8_t *data, *end;
00455 
00456     /* Seek to it */
00457     if (avio_seek(pb, video->data_offset, SEEK_SET) != video->data_offset)
00458         return AVERROR(EIO);
00459 
00460     /* Read the frame header */
00461     frame_header = avio_rl32(pb);
00462 
00463     frame_size      = (frame_header & 0x1FFFF) * 4 + 4;
00464     frame_timestamp = (frame_header >> 17);
00465 
00466     if ((frame_size + 4) > video->data_size)
00467         return AVERROR(EIO);
00468 
00469     /* Get the packet data */
00470     result = av_get_packet(pb, pkt, frame_size);
00471     if (result != frame_size)
00472         return result;
00473 
00474     /* Contrary to normal WMV2 video, the bit stream in XMV's
00475      * WMV2 is little-endian.
00476      * TODO: This manual swap is of course suboptimal.
00477      */
00478     for (data = pkt->data, end = pkt->data + frame_size; data < end; data += 4)
00479         AV_WB32(data, AV_RL32(data));
00480 
00481     pkt->stream_index = video->stream_index;
00482 
00483     /* Calculate the PTS */
00484 
00485     video->last_pts = frame_timestamp + video->pts;
00486 
00487     pkt->duration = 0;
00488     pkt->pts      = video->last_pts;
00489     pkt->dts      = AV_NOPTS_VALUE;
00490 
00491     video->pts += frame_timestamp;
00492 
00493     /* Keyframe? */
00494     pkt->flags = (pkt->data[0] & 0x80) ? 0 : AV_PKT_FLAG_KEY;
00495 
00496     /* Advance offset */
00497     video->data_size   -= frame_size + 4;
00498     video->data_offset += frame_size + 4;
00499 
00500     return 0;
00501 }
00502 
00503 static int xmv_read_packet(AVFormatContext *s,
00504                            AVPacket *pkt)
00505 {
00506     XMVDemuxContext *xmv = s->priv_data;
00507     int result;
00508 
00509     if (xmv->video.current_frame == xmv->video.frame_count) {
00510         /* No frames left in this packet, so we fetch a new one */
00511 
00512         result = xmv_fetch_new_packet(s);
00513         if (result)
00514             return result;
00515     }
00516 
00517     if (xmv->current_stream == 0) {
00518         /* Fetch a video frame */
00519 
00520         result = xmv_fetch_video_packet(s, pkt);
00521         if (result)
00522             return result;
00523 
00524     } else {
00525         /* Fetch an audio frame */
00526 
00527         result = xmv_fetch_audio_packet(s, pkt, xmv->current_stream - 1);
00528         if (result)
00529             return result;
00530     }
00531 
00532     /* Increase our counters */
00533     if (++xmv->current_stream >= xmv->stream_count) {
00534         xmv->current_stream       = 0;
00535         xmv->video.current_frame += 1;
00536     }
00537 
00538     return 0;
00539 }
00540 
00541 static int xmv_read_close(AVFormatContext *s)
00542 {
00543     XMVDemuxContext *xmv = s->priv_data;
00544 
00545     av_free(xmv->audio);
00546 
00547     return 0;
00548 }
00549 
00550 AVInputFormat ff_xmv_demuxer = {
00551     .name           = "xmv",
00552     .long_name      = NULL_IF_CONFIG_SMALL("Microsoft XMV"),
00553     .priv_data_size = sizeof(XMVDemuxContext),
00554     .read_probe     = xmv_probe,
00555     .read_header    = xmv_read_header,
00556     .read_packet    = xmv_read_packet,
00557     .read_close     = xmv_read_close,
00558 };
Generated on Fri Feb 1 2013 14:34:55 for FFmpeg by doxygen 1.7.1