/src/ffmpeg/libavformat/xmv.c
Line | Count | Source |
1 | | /* |
2 | | * Microsoft XMV demuxer |
3 | | * Copyright (c) 2011 Sven Hesse <drmccoy@drmccoy.de> |
4 | | * Copyright (c) 2011 Matthew Hoops <clone2727@gmail.com> |
5 | | * |
6 | | * This file is part of FFmpeg. |
7 | | * |
8 | | * FFmpeg is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public |
10 | | * License as published by the Free Software Foundation; either |
11 | | * version 2.1 of the License, or (at your option) any later version. |
12 | | * |
13 | | * FFmpeg is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with FFmpeg; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /** |
24 | | * @file |
25 | | * Microsoft XMV demuxer |
26 | | */ |
27 | | |
28 | | #include <inttypes.h> |
29 | | |
30 | | #include "libavutil/intreadwrite.h" |
31 | | #include "libavutil/mem.h" |
32 | | |
33 | | #include "avformat.h" |
34 | | #include "avio_internal.h" |
35 | | #include "demux.h" |
36 | | #include "internal.h" |
37 | | #include "riff.h" |
38 | | #include "libavutil/avassert.h" |
39 | | |
40 | | /** The min size of an XMV header. */ |
41 | 959k | #define XMV_MIN_HEADER_SIZE 36 |
42 | | |
43 | | /** Audio flag: ADPCM'd 5.1 stream, front left / right channels */ |
44 | 151k | #define XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT 1 |
45 | | /** Audio flag: ADPCM'd 5.1 stream, front center / low frequency channels */ |
46 | 151k | #define XMV_AUDIO_ADPCM51_FRONTCENTERLOW 2 |
47 | | /** Audio flag: ADPCM'd 5.1 stream, rear left / right channels */ |
48 | 151k | #define XMV_AUDIO_ADPCM51_REARLEFTRIGHT 4 |
49 | | |
50 | | /** Audio flag: Any of the ADPCM'd 5.1 stream flags. */ |
51 | 151k | #define XMV_AUDIO_ADPCM51 (XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT | \ |
52 | 151k | XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \ |
53 | 151k | XMV_AUDIO_ADPCM51_REARLEFTRIGHT) |
54 | | |
55 | 303k | #define XMV_BLOCK_ALIGN_SIZE 36 |
56 | | |
57 | | /** A video packet with an XMV file. */ |
58 | | typedef struct XMVVideoPacket { |
59 | | int created; |
60 | | int stream_index; ///< The decoder stream index for this video packet. |
61 | | |
62 | | uint32_t data_size; ///< The size of the remaining video data. |
63 | | uint64_t data_offset; ///< The offset of the video data within the file. |
64 | | |
65 | | uint32_t current_frame; ///< The current frame within this video packet. |
66 | | uint32_t frame_count; ///< The amount of frames within this video packet. |
67 | | |
68 | | int has_extradata; ///< Does the video packet contain extra data? |
69 | | uint8_t extradata[4]; ///< The extra data |
70 | | |
71 | | int64_t last_pts; ///< PTS of the last video frame. |
72 | | int64_t pts; ///< PTS of the most current video frame. |
73 | | } XMVVideoPacket; |
74 | | |
75 | | /** An audio packet with an XMV file. */ |
76 | | typedef struct XMVAudioPacket { |
77 | | int created; |
78 | | int stream_index; ///< The decoder stream index for this audio packet. |
79 | | |
80 | | /* Stream format properties. */ |
81 | | uint16_t compression; ///< The type of compression. |
82 | | uint16_t channels; ///< Number of channels. |
83 | | int32_t sample_rate; ///< Sampling rate. |
84 | | uint16_t bits_per_sample; ///< Bits per compressed sample. |
85 | | uint64_t bit_rate; ///< Bits of compressed data per second. |
86 | | uint16_t flags; ///< Flags |
87 | | unsigned block_align; ///< Bytes per compressed block. |
88 | | |
89 | | enum AVCodecID codec_id; ///< The codec ID of the compression scheme. |
90 | | |
91 | | uint32_t data_size; ///< The size of the remaining audio data. |
92 | | uint64_t data_offset; ///< The offset of the audio data within the file. |
93 | | |
94 | | uint32_t frame_size; ///< Number of bytes to put into an audio frame. |
95 | | } XMVAudioPacket; |
96 | | |
97 | | /** Context for demuxing an XMV file. */ |
98 | | typedef struct XMVDemuxContext { |
99 | | uint16_t audio_track_count; ///< Number of audio track in this file. |
100 | | |
101 | | uint32_t this_packet_size; ///< Size of the current packet. |
102 | | uint32_t next_packet_size; ///< Size of the next packet. |
103 | | |
104 | | uint64_t this_packet_offset; ///< Offset of the current packet. |
105 | | uint64_t next_packet_offset; ///< Offset of the next packet. |
106 | | |
107 | | uint16_t current_stream; ///< The index of the stream currently handling. |
108 | | uint16_t stream_count; ///< The number of streams in this file. |
109 | | |
110 | | uint32_t video_duration; |
111 | | uint32_t video_width; |
112 | | uint32_t video_height; |
113 | | |
114 | | XMVVideoPacket video; ///< The video packet contained in each packet. |
115 | | XMVAudioPacket *audio; ///< The audio packets contained in each packet. |
116 | | } XMVDemuxContext; |
117 | | |
118 | | static int xmv_probe(const AVProbeData *p) |
119 | 959k | { |
120 | 959k | uint32_t file_version; |
121 | | |
122 | 959k | if (p->buf_size < XMV_MIN_HEADER_SIZE) |
123 | 230k | return 0; |
124 | | |
125 | 728k | file_version = AV_RL32(p->buf + 16); |
126 | 728k | if ((file_version == 0) || (file_version > 4)) |
127 | 723k | return 0; |
128 | | |
129 | 4.98k | if (!memcmp(p->buf + 12, "xobX", 4)) |
130 | 309 | return AVPROBE_SCORE_MAX; |
131 | | |
132 | 4.68k | return 0; |
133 | 4.98k | } |
134 | | |
135 | | static int xmv_read_close(AVFormatContext *s) |
136 | 3.87k | { |
137 | 3.87k | XMVDemuxContext *xmv = s->priv_data; |
138 | | |
139 | 3.87k | av_freep(&xmv->audio); |
140 | | |
141 | 3.87k | return 0; |
142 | 3.87k | } |
143 | | |
144 | | static int xmv_read_header(AVFormatContext *s) |
145 | 3.87k | { |
146 | 3.87k | XMVDemuxContext *xmv = s->priv_data; |
147 | 3.87k | AVIOContext *pb = s->pb; |
148 | | |
149 | 3.87k | uint32_t file_version; |
150 | 3.87k | uint32_t this_packet_size; |
151 | 3.87k | uint16_t audio_track; |
152 | | |
153 | 3.87k | s->ctx_flags |= AVFMTCTX_NOHEADER; |
154 | | |
155 | 3.87k | avio_skip(pb, 4); /* Next packet size */ |
156 | | |
157 | 3.87k | this_packet_size = avio_rl32(pb); |
158 | | |
159 | 3.87k | avio_skip(pb, 4); /* Max packet size */ |
160 | 3.87k | avio_skip(pb, 4); /* "xobX" */ |
161 | | |
162 | 3.87k | file_version = avio_rl32(pb); |
163 | 3.87k | if ((file_version != 4) && (file_version != 2)) |
164 | 3.74k | avpriv_request_sample(s, "Uncommon version %"PRIu32"", file_version); |
165 | | |
166 | | /* Video tracks */ |
167 | | |
168 | 3.87k | xmv->video_width = avio_rl32(pb); |
169 | 3.87k | xmv->video_height = avio_rl32(pb); |
170 | 3.87k | xmv->video_duration = avio_rl32(pb); |
171 | | |
172 | | /* Audio tracks */ |
173 | | |
174 | 3.87k | xmv->audio_track_count = avio_rl16(pb); |
175 | | |
176 | 3.87k | avio_skip(pb, 2); /* Unknown (padding?) */ |
177 | | |
178 | 3.87k | xmv->audio = av_calloc(xmv->audio_track_count, sizeof(*xmv->audio)); |
179 | 3.87k | if (!xmv->audio) |
180 | 0 | return AVERROR(ENOMEM); |
181 | | |
182 | 155k | for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) { |
183 | 151k | XMVAudioPacket *packet = &xmv->audio[audio_track]; |
184 | | |
185 | 151k | packet->compression = avio_rl16(pb); |
186 | 151k | packet->channels = avio_rl16(pb); |
187 | 151k | packet->sample_rate = avio_rl32(pb); |
188 | 151k | packet->bits_per_sample = avio_rl16(pb); |
189 | 151k | packet->flags = avio_rl16(pb); |
190 | | |
191 | 151k | packet->bit_rate = (uint64_t)packet->bits_per_sample * |
192 | 151k | packet->sample_rate * |
193 | 151k | packet->channels; |
194 | 151k | packet->block_align = XMV_BLOCK_ALIGN_SIZE * packet->channels; |
195 | 151k | packet->codec_id = ff_wav_codec_get_id(packet->compression, |
196 | 151k | packet->bits_per_sample); |
197 | | |
198 | 151k | packet->stream_index = -1; |
199 | | |
200 | 151k | packet->frame_size = 0; |
201 | | |
202 | | /* TODO: ADPCM'd 5.1 sound is encoded in three separate streams. |
203 | | * Those need to be interleaved to a proper 5.1 stream. */ |
204 | 151k | if (packet->flags & XMV_AUDIO_ADPCM51) |
205 | 127k | av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream " |
206 | 127k | "(0x%04X)\n", packet->flags); |
207 | | |
208 | 151k | if (!packet->channels || packet->sample_rate <= 0 || |
209 | 151k | packet->channels >= UINT16_MAX / XMV_BLOCK_ALIGN_SIZE) { |
210 | 383 | av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %"PRIu16".\n", |
211 | 383 | audio_track); |
212 | 383 | return AVERROR_INVALIDDATA; |
213 | 383 | } |
214 | 151k | } |
215 | | |
216 | | |
217 | | /* Initialize the packet context */ |
218 | | |
219 | 3.48k | xmv->next_packet_offset = avio_tell(pb); |
220 | 3.48k | if (this_packet_size < xmv->next_packet_offset) |
221 | 52 | return AVERROR_INVALIDDATA; |
222 | 3.43k | xmv->next_packet_size = this_packet_size - xmv->next_packet_offset; |
223 | 3.43k | xmv->stream_count = xmv->audio_track_count + 1; |
224 | | |
225 | 3.43k | return 0; |
226 | 3.48k | } |
227 | | |
228 | | static void xmv_read_extradata(uint8_t *extradata, AVIOContext *pb) |
229 | 2.02k | { |
230 | | /* Read the XMV extradata */ |
231 | | |
232 | 2.02k | uint32_t data = avio_rl32(pb); |
233 | | |
234 | 2.02k | int mspel_bit = !!(data & 0x01); |
235 | 2.02k | int loop_filter = !!(data & 0x02); |
236 | 2.02k | int abt_flag = !!(data & 0x04); |
237 | 2.02k | int j_type_bit = !!(data & 0x08); |
238 | 2.02k | int top_left_mv_flag = !!(data & 0x10); |
239 | 2.02k | int per_mb_rl_bit = !!(data & 0x20); |
240 | 2.02k | int slice_count = (data >> 6) & 7; |
241 | | |
242 | | /* Write it back as standard WMV2 extradata */ |
243 | | |
244 | 2.02k | data = 0; |
245 | | |
246 | 2.02k | data |= mspel_bit << 15; |
247 | 2.02k | data |= loop_filter << 14; |
248 | 2.02k | data |= abt_flag << 13; |
249 | 2.02k | data |= j_type_bit << 12; |
250 | 2.02k | data |= top_left_mv_flag << 11; |
251 | 2.02k | data |= per_mb_rl_bit << 10; |
252 | 2.02k | data |= slice_count << 7; |
253 | | |
254 | 2.02k | AV_WB32(extradata, data); |
255 | 2.02k | } |
256 | | |
257 | | static int xmv_process_packet_header(AVFormatContext *s) |
258 | 17.2k | { |
259 | 17.2k | XMVDemuxContext *xmv = s->priv_data; |
260 | 17.2k | AVIOContext *pb = s->pb; |
261 | 17.2k | int ret; |
262 | | |
263 | 17.2k | uint8_t data[8]; |
264 | 17.2k | uint16_t audio_track; |
265 | 17.2k | uint64_t data_offset; |
266 | | |
267 | | /* Next packet size */ |
268 | 17.2k | xmv->next_packet_size = avio_rl32(pb); |
269 | | |
270 | | /* Packet video header */ |
271 | | |
272 | 17.2k | if ((ret = ffio_read_size(pb, data, 8)) < 0) |
273 | 560 | return ret; |
274 | | |
275 | 16.6k | xmv->video.data_size = AV_RL32(data) & 0x007FFFFF; |
276 | | |
277 | 16.6k | xmv->video.current_frame = 0; |
278 | 16.6k | xmv->video.frame_count = (AV_RL32(data) >> 23) & 0xFF; |
279 | | |
280 | 16.6k | xmv->video.has_extradata = (data[3] & 0x80) != 0; |
281 | | |
282 | 16.6k | if (!xmv->video.created) { |
283 | 3.12k | AVStream *vst = avformat_new_stream(s, NULL); |
284 | 3.12k | if (!vst) |
285 | 0 | return AVERROR(ENOMEM); |
286 | | |
287 | 3.12k | avpriv_set_pts_info(vst, 32, 1, 1000); |
288 | | |
289 | 3.12k | vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; |
290 | 3.12k | vst->codecpar->codec_id = AV_CODEC_ID_WMV2; |
291 | 3.12k | vst->codecpar->codec_tag = MKBETAG('W', 'M', 'V', '2'); |
292 | 3.12k | vst->codecpar->width = xmv->video_width; |
293 | 3.12k | vst->codecpar->height = xmv->video_height; |
294 | | |
295 | 3.12k | vst->duration = xmv->video_duration; |
296 | | |
297 | 3.12k | xmv->video.stream_index = vst->index; |
298 | | |
299 | 3.12k | xmv->video.created = 1; |
300 | 3.12k | } |
301 | | |
302 | | /* Adding the audio data sizes and the video data size keeps you 4 bytes |
303 | | * short for every audio track. But as playing around with XMV files with |
304 | | * ADPCM audio showed, taking the extra 4 bytes from the audio data gives |
305 | | * you either completely distorted audio or click (when skipping the |
306 | | * remaining 68 bytes of the ADPCM block). Subtracting 4 bytes for every |
307 | | * audio track from the video data works at least for the audio. Probably |
308 | | * some alignment thing? |
309 | | * The video data has (always?) lots of padding, so it should work out... |
310 | | */ |
311 | 16.6k | xmv->video.data_size -= xmv->audio_track_count * 4; |
312 | | |
313 | 16.6k | xmv->current_stream = 0; |
314 | 16.6k | if (!xmv->video.frame_count) { |
315 | 12.7k | xmv->video.frame_count = 1; |
316 | 12.7k | xmv->current_stream = xmv->stream_count > 1; |
317 | 12.7k | } |
318 | | |
319 | | /* Packet audio header */ |
320 | | |
321 | 119k | for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) { |
322 | 104k | XMVAudioPacket *packet = &xmv->audio[audio_track]; |
323 | | |
324 | 104k | if ((ret = ffio_read_size(pb, data, 4)) < 0) |
325 | 631 | return ret; |
326 | | |
327 | 103k | if (!packet->created) { |
328 | 62.2k | AVStream *ast = avformat_new_stream(s, NULL); |
329 | 62.2k | if (!ast) |
330 | 39 | return AVERROR(ENOMEM); |
331 | | |
332 | 62.2k | ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
333 | 62.2k | ast->codecpar->codec_id = packet->codec_id; |
334 | 62.2k | ast->codecpar->codec_tag = packet->compression; |
335 | 62.2k | ast->codecpar->ch_layout.nb_channels = packet->channels; |
336 | 62.2k | ast->codecpar->sample_rate = packet->sample_rate; |
337 | 62.2k | ast->codecpar->bits_per_coded_sample = packet->bits_per_sample; |
338 | 62.2k | ast->codecpar->bit_rate = packet->bit_rate; |
339 | 62.2k | ast->codecpar->block_align = 36 * packet->channels; |
340 | | |
341 | 62.2k | avpriv_set_pts_info(ast, 32, 1, packet->sample_rate); |
342 | | |
343 | 62.2k | packet->stream_index = ast->index; |
344 | | |
345 | 62.2k | ast->duration = xmv->video_duration; |
346 | | |
347 | 62.2k | packet->created = 1; |
348 | 62.2k | } |
349 | | |
350 | 103k | packet->data_size = AV_RL32(data) & 0x007FFFFF; |
351 | 103k | if ((packet->data_size == 0) && (audio_track != 0)) |
352 | | /* This happens when I create an XMV with several identical audio |
353 | | * streams. From the size calculations, duplicating the previous |
354 | | * stream's size works out, but the track data itself is silent. |
355 | | * Maybe this should also redirect the offset to the previous track? |
356 | | */ |
357 | 13.8k | packet->data_size = xmv->audio[audio_track - 1].data_size; |
358 | | |
359 | | /* Carve up the audio data in frame_count slices */ |
360 | 103k | packet->frame_size = packet->data_size / xmv->video.frame_count; |
361 | 103k | packet->frame_size -= packet->frame_size % packet->block_align; |
362 | 103k | } |
363 | | |
364 | | /* Packet data offsets */ |
365 | | |
366 | 15.9k | data_offset = avio_tell(pb); |
367 | | |
368 | 15.9k | xmv->video.data_offset = data_offset; |
369 | 15.9k | data_offset += xmv->video.data_size; |
370 | | |
371 | 52.5k | for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) { |
372 | 36.5k | xmv->audio[audio_track].data_offset = data_offset; |
373 | 36.5k | data_offset += xmv->audio[audio_track].data_size; |
374 | 36.5k | } |
375 | | |
376 | | /* Video frames header */ |
377 | | |
378 | | /* Read new video extra data */ |
379 | 15.9k | if (xmv->video.data_size > 0) { |
380 | 15.3k | if (xmv->video.has_extradata) { |
381 | 2.02k | xmv_read_extradata(xmv->video.extradata, pb); |
382 | | |
383 | 2.02k | xmv->video.data_size -= 4; |
384 | 2.02k | xmv->video.data_offset += 4; |
385 | | |
386 | 2.02k | if (xmv->video.stream_index >= 0) { |
387 | 2.02k | AVStream *vst = s->streams[xmv->video.stream_index]; |
388 | | |
389 | 2.02k | av_assert0(xmv->video.stream_index < s->nb_streams); |
390 | | |
391 | 2.02k | if (vst->codecpar->extradata_size < 4) { |
392 | 1.03k | if ((ret = ff_alloc_extradata(vst->codecpar, 4)) < 0) |
393 | 0 | return ret; |
394 | 1.03k | } |
395 | | |
396 | 2.02k | memcpy(vst->codecpar->extradata, xmv->video.extradata, 4); |
397 | 2.02k | } |
398 | 2.02k | } |
399 | 15.3k | } |
400 | | |
401 | 15.9k | return 0; |
402 | 15.9k | } |
403 | | |
404 | | static int xmv_fetch_new_packet(AVFormatContext *s) |
405 | 20.4k | { |
406 | 20.4k | XMVDemuxContext *xmv = s->priv_data; |
407 | 20.4k | AVIOContext *pb = s->pb; |
408 | 20.4k | int result; |
409 | | |
410 | 20.4k | if (xmv->next_packet_size == 0) |
411 | 517 | return AVERROR_EOF; |
412 | | |
413 | | /* Seek to it */ |
414 | 19.9k | xmv->this_packet_offset = xmv->next_packet_offset; |
415 | 19.9k | if (avio_seek(pb, xmv->this_packet_offset, SEEK_SET) != xmv->this_packet_offset) |
416 | 2.66k | return AVERROR_INVALIDDATA; |
417 | | |
418 | | /* Update the size */ |
419 | 17.2k | xmv->this_packet_size = xmv->next_packet_size; |
420 | 17.2k | if (xmv->this_packet_size < (12 + xmv->audio_track_count * 4)) |
421 | 42 | return AVERROR_INVALIDDATA; |
422 | | |
423 | | /* Process the header */ |
424 | 17.2k | result = xmv_process_packet_header(s); |
425 | 17.2k | if (result) |
426 | 1.23k | return result; |
427 | | |
428 | | /* Update the offset */ |
429 | 15.9k | xmv->next_packet_offset = xmv->this_packet_offset + xmv->this_packet_size; |
430 | | |
431 | 15.9k | return 0; |
432 | 17.2k | } |
433 | | |
434 | | static int xmv_fetch_audio_packet(AVFormatContext *s, |
435 | | AVPacket *pkt, uint32_t stream) |
436 | 687k | { |
437 | 687k | XMVDemuxContext *xmv = s->priv_data; |
438 | 687k | AVIOContext *pb = s->pb; |
439 | 687k | XMVAudioPacket *audio = &xmv->audio[stream]; |
440 | | |
441 | 687k | uint32_t data_size; |
442 | 687k | int result; |
443 | | |
444 | | /* Seek to it */ |
445 | 687k | if (avio_seek(pb, audio->data_offset, SEEK_SET) != audio->data_offset) |
446 | 886 | return AVERROR_INVALIDDATA; |
447 | | |
448 | 686k | if ((xmv->video.current_frame + 1) < xmv->video.frame_count) |
449 | | /* Not the last frame, get at most frame_size bytes. */ |
450 | 587k | data_size = FFMIN(audio->frame_size, audio->data_size); |
451 | 99.1k | else |
452 | | /* Last frame, get the rest. */ |
453 | 99.1k | data_size = audio->data_size; |
454 | | |
455 | | /* Read the packet */ |
456 | 686k | result = av_get_packet(pb, pkt, data_size); |
457 | 686k | if (result <= 0) |
458 | 628k | return result; |
459 | | |
460 | 57.5k | pkt->stream_index = audio->stream_index; |
461 | | |
462 | | /* Advance offset */ |
463 | 57.5k | audio->data_size -= data_size; |
464 | 57.5k | audio->data_offset += data_size; |
465 | | |
466 | 57.5k | return 0; |
467 | 686k | } |
468 | | |
469 | | static int xmv_fetch_video_packet(AVFormatContext *s, |
470 | | AVPacket *pkt) |
471 | 94.6k | { |
472 | 94.6k | XMVDemuxContext *xmv = s->priv_data; |
473 | 94.6k | AVIOContext *pb = s->pb; |
474 | 94.6k | XMVVideoPacket *video = &xmv->video; |
475 | | |
476 | 94.6k | int result; |
477 | 94.6k | uint32_t frame_header; |
478 | 94.6k | uint32_t frame_size, frame_timestamp; |
479 | 94.6k | uint8_t *data, *end; |
480 | | |
481 | | /* Seek to it */ |
482 | 94.6k | if (avio_seek(pb, video->data_offset, SEEK_SET) != video->data_offset) |
483 | 159 | return AVERROR_INVALIDDATA; |
484 | | |
485 | | /* Read the frame header */ |
486 | 94.4k | frame_header = avio_rl32(pb); |
487 | | |
488 | 94.4k | frame_size = (frame_header & 0x1FFFF) * 4 + 4; |
489 | 94.4k | frame_timestamp = (frame_header >> 17); |
490 | | |
491 | 94.4k | if ((frame_size + 4) > video->data_size) |
492 | 242 | return AVERROR_INVALIDDATA; |
493 | | |
494 | | /* Get the packet data */ |
495 | 94.2k | result = av_get_packet(pb, pkt, frame_size); |
496 | 94.2k | if (result != frame_size) |
497 | 10.5k | return result; |
498 | | |
499 | | /* Contrary to normal WMV2 video, the bit stream in XMV's |
500 | | * WMV2 is little-endian. |
501 | | * TODO: This manual swap is of course suboptimal. |
502 | | */ |
503 | 29.9M | for (data = pkt->data, end = pkt->data + frame_size; data < end; data += 4) |
504 | 29.8M | AV_WB32(data, AV_RL32(data)); |
505 | | |
506 | 83.6k | pkt->stream_index = video->stream_index; |
507 | | |
508 | | /* Calculate the PTS */ |
509 | | |
510 | 83.6k | video->last_pts = frame_timestamp + video->pts; |
511 | | |
512 | 83.6k | pkt->duration = 0; |
513 | 83.6k | pkt->pts = video->last_pts; |
514 | 83.6k | pkt->dts = AV_NOPTS_VALUE; |
515 | | |
516 | 83.6k | video->pts += frame_timestamp; |
517 | | |
518 | | /* Keyframe? */ |
519 | 83.6k | pkt->flags = (pkt->data[0] & 0x80) ? 0 : AV_PKT_FLAG_KEY; |
520 | | |
521 | | /* Advance offset */ |
522 | 83.6k | video->data_size -= frame_size + 4; |
523 | 83.6k | video->data_offset += frame_size + 4; |
524 | | |
525 | 83.6k | return 0; |
526 | 94.2k | } |
527 | | |
528 | | static int xmv_read_packet(AVFormatContext *s, |
529 | | AVPacket *pkt) |
530 | 786k | { |
531 | 786k | XMVDemuxContext *xmv = s->priv_data; |
532 | 786k | int result; |
533 | | |
534 | 786k | if (xmv->video.current_frame == xmv->video.frame_count) { |
535 | | /* No frames left in this packet, so we fetch a new one */ |
536 | | |
537 | 20.4k | result = xmv_fetch_new_packet(s); |
538 | 20.4k | if (result) |
539 | 4.45k | return result; |
540 | 20.4k | } |
541 | | |
542 | 781k | if (xmv->current_stream == 0) { |
543 | | /* Fetch a video frame */ |
544 | | |
545 | 94.6k | result = xmv_fetch_video_packet(s, pkt); |
546 | 687k | } else { |
547 | | /* Fetch an audio frame */ |
548 | | |
549 | 687k | result = xmv_fetch_audio_packet(s, pkt, xmv->current_stream - 1); |
550 | 687k | } |
551 | 781k | if (result) { |
552 | 12.0k | xmv->current_stream = 0; |
553 | 12.0k | xmv->video.current_frame = xmv->video.frame_count; |
554 | 12.0k | return result; |
555 | 12.0k | } |
556 | | |
557 | | |
558 | | /* Increase our counters */ |
559 | 769k | if (++xmv->current_stream >= xmv->stream_count) { |
560 | 86.7k | xmv->current_stream = 0; |
561 | 86.7k | xmv->video.current_frame += 1; |
562 | 86.7k | } |
563 | | |
564 | 769k | return 0; |
565 | 781k | } |
566 | | |
567 | | const FFInputFormat ff_xmv_demuxer = { |
568 | | .p.name = "xmv", |
569 | | .p.long_name = NULL_IF_CONFIG_SMALL("Microsoft XMV"), |
570 | | .p.extensions = "xmv", |
571 | | .priv_data_size = sizeof(XMVDemuxContext), |
572 | | .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP, |
573 | | .read_probe = xmv_probe, |
574 | | .read_header = xmv_read_header, |
575 | | .read_packet = xmv_read_packet, |
576 | | .read_close = xmv_read_close, |
577 | | }; |