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