ipmovie.c
Go to the documentation of this file.
1 /*
2  * Interplay MVE File Demuxer
3  * Copyright (c) 2003 The ffmpeg Project
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
35 #include "libavutil/intreadwrite.h"
36 #include "avformat.h"
37 #include "internal.h"
38 
39 #define CHUNK_PREAMBLE_SIZE 4
40 #define OPCODE_PREAMBLE_SIZE 4
41 
42 #define CHUNK_INIT_AUDIO 0x0000
43 #define CHUNK_AUDIO_ONLY 0x0001
44 #define CHUNK_INIT_VIDEO 0x0002
45 #define CHUNK_VIDEO 0x0003
46 #define CHUNK_SHUTDOWN 0x0004
47 #define CHUNK_END 0x0005
48 /* these last types are used internally */
49 #define CHUNK_DONE 0xFFFC
50 #define CHUNK_NOMEM 0xFFFD
51 #define CHUNK_EOF 0xFFFE
52 #define CHUNK_BAD 0xFFFF
53 
54 #define OPCODE_END_OF_STREAM 0x00
55 #define OPCODE_END_OF_CHUNK 0x01
56 #define OPCODE_CREATE_TIMER 0x02
57 #define OPCODE_INIT_AUDIO_BUFFERS 0x03
58 #define OPCODE_START_STOP_AUDIO 0x04
59 #define OPCODE_INIT_VIDEO_BUFFERS 0x05
60 #define OPCODE_UNKNOWN_06 0x06
61 #define OPCODE_SEND_BUFFER 0x07
62 #define OPCODE_AUDIO_FRAME 0x08
63 #define OPCODE_SILENCE_FRAME 0x09
64 #define OPCODE_INIT_VIDEO_MODE 0x0A
65 #define OPCODE_CREATE_GRADIENT 0x0B
66 #define OPCODE_SET_PALETTE 0x0C
67 #define OPCODE_SET_PALETTE_COMPRESSED 0x0D
68 #define OPCODE_UNKNOWN_0E 0x0E
69 #define OPCODE_SET_DECODING_MAP 0x0F
70 #define OPCODE_UNKNOWN_10 0x10
71 #define OPCODE_VIDEO_DATA 0x11
72 #define OPCODE_UNKNOWN_12 0x12
73 #define OPCODE_UNKNOWN_13 0x13
74 #define OPCODE_UNKNOWN_14 0x14
75 #define OPCODE_UNKNOWN_15 0x15
76 
77 #define PALETTE_COUNT 256
78 
79 typedef struct IPMVEContext {
80 
81  unsigned char *buf;
82  int buf_size;
83 
84  uint64_t frame_pts_inc;
85 
86  unsigned int video_bpp;
87  unsigned int video_width;
88  unsigned int video_height;
89  int64_t video_pts;
90  uint32_t palette[256];
92  int changed;
93 
94  unsigned int audio_bits;
95  unsigned int audio_channels;
96  unsigned int audio_sample_rate;
98  unsigned int audio_frame_count;
99 
102 
109 
111 
112 } IPMVEContext;
113 
115  AVPacket *pkt) {
116 
117  int chunk_type;
118 
119  if (s->audio_chunk_offset) {
120  if (s->audio_type == CODEC_ID_NONE) {
121  av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before"
122  "audio codec is known\n");
123  return CHUNK_BAD;
124  }
125 
126  /* adjust for PCM audio by skipping chunk header */
128  s->audio_chunk_offset += 6;
129  s->audio_chunk_size -= 6;
130  }
131 
132  avio_seek(pb, s->audio_chunk_offset, SEEK_SET);
133  s->audio_chunk_offset = 0;
134 
135  if (s->audio_chunk_size != av_get_packet(pb, pkt, s->audio_chunk_size))
136  return CHUNK_EOF;
137 
139  pkt->pts = s->audio_frame_count;
140 
141  /* audio frame maintenance */
143  s->audio_frame_count +=
144  (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8));
145  else
146  s->audio_frame_count +=
148 
149  av_dlog(NULL, "sending audio frame with pts %"PRId64" (%d audio frames)\n",
150  pkt->pts, s->audio_frame_count);
151 
152  chunk_type = CHUNK_VIDEO;
153 
154  } else if (s->decode_map_chunk_offset) {
155 
156  /* send both the decode map and the video data together */
157 
159  return CHUNK_NOMEM;
160 
161  if (s->has_palette) {
162  uint8_t *pal;
163 
166  if (pal) {
167  memcpy(pal, s->palette, AVPALETTE_SIZE);
168  s->has_palette = 0;
169  }
170  }
171 
172  if (s->changed) {
173  ff_add_param_change(pkt, 0, 0, 0, s->video_width, s->video_height);
174  s->changed = 0;
175  }
176  pkt->pos= s->decode_map_chunk_offset;
177  avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET);
179 
180  if (avio_read(pb, pkt->data, s->decode_map_chunk_size) !=
182  av_free_packet(pkt);
183  return CHUNK_EOF;
184  }
185 
186  avio_seek(pb, s->video_chunk_offset, SEEK_SET);
187  s->video_chunk_offset = 0;
188 
189  if (avio_read(pb, pkt->data + s->decode_map_chunk_size,
191  av_free_packet(pkt);
192  return CHUNK_EOF;
193  }
194 
196  pkt->pts = s->video_pts;
197 
198  av_dlog(NULL, "sending video frame with pts %"PRId64"\n", pkt->pts);
199 
200  s->video_pts += s->frame_pts_inc;
201 
202  chunk_type = CHUNK_VIDEO;
203 
204  } else {
205 
206  avio_seek(pb, s->next_chunk_offset, SEEK_SET);
207  chunk_type = CHUNK_DONE;
208 
209  }
210 
211  return chunk_type;
212 }
213 
214 /* This function loads and processes a single chunk in an IP movie file.
215  * It returns the type of chunk that was processed. */
217  AVPacket *pkt)
218 {
219  unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
220  int chunk_type;
221  int chunk_size;
222  unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE];
223  unsigned char opcode_type;
224  unsigned char opcode_version;
225  int opcode_size;
226  unsigned char scratch[1024];
227  int i, j;
228  int first_color, last_color;
229  int audio_flags;
230  unsigned char r, g, b;
231  unsigned int width, height;
232 
233  /* see if there are any pending packets */
234  chunk_type = load_ipmovie_packet(s, pb, pkt);
235  if (chunk_type != CHUNK_DONE)
236  return chunk_type;
237 
238  /* read the next chunk, wherever the file happens to be pointing */
239  if (pb->eof_reached)
240  return CHUNK_EOF;
241  if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
243  return CHUNK_BAD;
244  chunk_size = AV_RL16(&chunk_preamble[0]);
245  chunk_type = AV_RL16(&chunk_preamble[2]);
246 
247  av_dlog(NULL, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size);
248 
249  switch (chunk_type) {
250 
251  case CHUNK_INIT_AUDIO:
252  av_dlog(NULL, "initialize audio\n");
253  break;
254 
255  case CHUNK_AUDIO_ONLY:
256  av_dlog(NULL, "audio only\n");
257  break;
258 
259  case CHUNK_INIT_VIDEO:
260  av_dlog(NULL, "initialize video\n");
261  break;
262 
263  case CHUNK_VIDEO:
264  av_dlog(NULL, "video (and audio)\n");
265  break;
266 
267  case CHUNK_SHUTDOWN:
268  av_dlog(NULL, "shutdown\n");
269  break;
270 
271  case CHUNK_END:
272  av_dlog(NULL, "end\n");
273  break;
274 
275  default:
276  av_dlog(NULL, "invalid chunk\n");
277  chunk_type = CHUNK_BAD;
278  break;
279 
280  }
281 
282  while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) {
283 
284  /* read the next chunk, wherever the file happens to be pointing */
285  if (pb->eof_reached) {
286  chunk_type = CHUNK_EOF;
287  break;
288  }
289  if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) !=
291  chunk_type = CHUNK_BAD;
292  break;
293  }
294 
295  opcode_size = AV_RL16(&opcode_preamble[0]);
296  opcode_type = opcode_preamble[2];
297  opcode_version = opcode_preamble[3];
298 
299  chunk_size -= OPCODE_PREAMBLE_SIZE;
300  chunk_size -= opcode_size;
301  if (chunk_size < 0) {
302  av_dlog(NULL, "chunk_size countdown just went negative\n");
303  chunk_type = CHUNK_BAD;
304  break;
305  }
306 
307  av_dlog(NULL, " opcode type %02X, version %d, 0x%04X bytes: ",
308  opcode_type, opcode_version, opcode_size);
309  switch (opcode_type) {
310 
312  av_dlog(NULL, "end of stream\n");
313  avio_skip(pb, opcode_size);
314  break;
315 
316  case OPCODE_END_OF_CHUNK:
317  av_dlog(NULL, "end of chunk\n");
318  avio_skip(pb, opcode_size);
319  break;
320 
321  case OPCODE_CREATE_TIMER:
322  av_dlog(NULL, "create timer\n");
323  if ((opcode_version > 0) || (opcode_size > 6)) {
324  av_dlog(NULL, "bad create_timer opcode\n");
325  chunk_type = CHUNK_BAD;
326  break;
327  }
328  if (avio_read(pb, scratch, opcode_size) !=
329  opcode_size) {
330  chunk_type = CHUNK_BAD;
331  break;
332  }
333  s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]);
334  av_dlog(NULL, " %.2f frames/second (timer div = %d, subdiv = %d)\n",
335  1000000.0 / s->frame_pts_inc, AV_RL32(&scratch[0]),
336  AV_RL16(&scratch[4]));
337  break;
338 
340  av_dlog(NULL, "initialize audio buffers\n");
341  if ((opcode_version > 1) || (opcode_size > 10)) {
342  av_dlog(NULL, "bad init_audio_buffers opcode\n");
343  chunk_type = CHUNK_BAD;
344  break;
345  }
346  if (avio_read(pb, scratch, opcode_size) !=
347  opcode_size) {
348  chunk_type = CHUNK_BAD;
349  break;
350  }
351  s->audio_sample_rate = AV_RL16(&scratch[4]);
352  audio_flags = AV_RL16(&scratch[2]);
353  /* bit 0 of the flags: 0 = mono, 1 = stereo */
354  s->audio_channels = (audio_flags & 1) + 1;
355  /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */
356  s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8;
357  /* bit 2 indicates compressed audio in version 1 opcode */
358  if ((opcode_version == 1) && (audio_flags & 0x4))
360  else if (s->audio_bits == 16)
362  else
364  av_dlog(NULL, "audio: %d bits, %d Hz, %s, %s format\n",
366  (s->audio_channels == 2) ? "stereo" : "mono",
368  "Interplay audio" : "PCM");
369  break;
370 
372  av_dlog(NULL, "start/stop audio\n");
373  avio_skip(pb, opcode_size);
374  break;
375 
377  av_dlog(NULL, "initialize video buffers\n");
378  if ((opcode_version > 2) || (opcode_size > 8)) {
379  av_dlog(NULL, "bad init_video_buffers opcode\n");
380  chunk_type = CHUNK_BAD;
381  break;
382  }
383  if (avio_read(pb, scratch, opcode_size) !=
384  opcode_size) {
385  chunk_type = CHUNK_BAD;
386  break;
387  }
388  width = AV_RL16(&scratch[0]) * 8;
389  height = AV_RL16(&scratch[2]) * 8;
390  if (width != s->video_width) {
391  s->video_width = width;
392  s->changed++;
393  }
394  if (height != s->video_height) {
395  s->video_height = height;
396  s->changed++;
397  }
398  if (opcode_version < 2 || !AV_RL16(&scratch[6])) {
399  s->video_bpp = 8;
400  } else {
401  s->video_bpp = 16;
402  }
403  av_dlog(NULL, "video resolution: %d x %d\n",
404  s->video_width, s->video_height);
405  break;
406 
407  case OPCODE_UNKNOWN_06:
408  case OPCODE_UNKNOWN_0E:
409  case OPCODE_UNKNOWN_10:
410  case OPCODE_UNKNOWN_12:
411  case OPCODE_UNKNOWN_13:
412  case OPCODE_UNKNOWN_14:
413  case OPCODE_UNKNOWN_15:
414  av_dlog(NULL, "unknown (but documented) opcode %02X\n", opcode_type);
415  avio_skip(pb, opcode_size);
416  break;
417 
418  case OPCODE_SEND_BUFFER:
419  av_dlog(NULL, "send buffer\n");
420  avio_skip(pb, opcode_size);
421  break;
422 
423  case OPCODE_AUDIO_FRAME:
424  av_dlog(NULL, "audio frame\n");
425 
426  /* log position and move on for now */
427  s->audio_chunk_offset = avio_tell(pb);
428  s->audio_chunk_size = opcode_size;
429  avio_skip(pb, opcode_size);
430  break;
431 
433  av_dlog(NULL, "silence frame\n");
434  avio_skip(pb, opcode_size);
435  break;
436 
438  av_dlog(NULL, "initialize video mode\n");
439  avio_skip(pb, opcode_size);
440  break;
441 
443  av_dlog(NULL, "create gradient\n");
444  avio_skip(pb, opcode_size);
445  break;
446 
447  case OPCODE_SET_PALETTE:
448  av_dlog(NULL, "set palette\n");
449  /* check for the logical maximum palette size
450  * (3 * 256 + 4 bytes) */
451  if (opcode_size > 0x304) {
452  av_dlog(NULL, "demux_ipmovie: set_palette opcode too large\n");
453  chunk_type = CHUNK_BAD;
454  break;
455  }
456  if (avio_read(pb, scratch, opcode_size) != opcode_size) {
457  chunk_type = CHUNK_BAD;
458  break;
459  }
460 
461  /* load the palette into internal data structure */
462  first_color = AV_RL16(&scratch[0]);
463  last_color = first_color + AV_RL16(&scratch[2]) - 1;
464  /* sanity check (since they are 16 bit values) */
465  if ((first_color > 0xFF) || (last_color > 0xFF)) {
466  av_dlog(NULL, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n",
467  first_color, last_color);
468  chunk_type = CHUNK_BAD;
469  break;
470  }
471  j = 4; /* offset of first palette data */
472  for (i = first_color; i <= last_color; i++) {
473  /* the palette is stored as a 6-bit VGA palette, thus each
474  * component is shifted up to a 8-bit range */
475  r = scratch[j++] * 4;
476  g = scratch[j++] * 4;
477  b = scratch[j++] * 4;
478  s->palette[i] = (r << 16) | (g << 8) | (b);
479  }
480  s->has_palette = 1;
481  break;
482 
484  av_dlog(NULL, "set palette compressed\n");
485  avio_skip(pb, opcode_size);
486  break;
487 
489  av_dlog(NULL, "set decoding map\n");
490 
491  /* log position and move on for now */
493  s->decode_map_chunk_size = opcode_size;
494  avio_skip(pb, opcode_size);
495  break;
496 
497  case OPCODE_VIDEO_DATA:
498  av_dlog(NULL, "set video data\n");
499 
500  /* log position and move on for now */
501  s->video_chunk_offset = avio_tell(pb);
502  s->video_chunk_size = opcode_size;
503  avio_skip(pb, opcode_size);
504  break;
505 
506  default:
507  av_dlog(NULL, "*** unknown opcode type\n");
508  chunk_type = CHUNK_BAD;
509  break;
510 
511  }
512  }
513 
514  /* make a note of where the stream is sitting */
515  s->next_chunk_offset = avio_tell(pb);
516 
517  /* dispatch the first of any pending packets */
518  if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY))
519  chunk_type = load_ipmovie_packet(s, pb, pkt);
520 
521  return chunk_type;
522 }
523 
524 static const char signature[] = "Interplay MVE File\x1A\0\x1A";
525 
527 {
528  uint8_t *b = p->buf;
529  uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
530  do {
531  if (memcmp(b++, signature, sizeof(signature)) == 0)
532  return AVPROBE_SCORE_MAX;
533  } while (b < b_end);
534 
535  return 0;
536 }
537 
539  AVFormatParameters *ap)
540 {
541  IPMVEContext *ipmovie = s->priv_data;
542  AVIOContext *pb = s->pb;
543  AVPacket pkt;
544  AVStream *st;
545  unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
546  int chunk_type;
547  uint8_t signature_buffer[sizeof(signature)];
548 
549  avio_read(pb, signature_buffer, sizeof(signature_buffer));
550  while (memcmp(signature_buffer, signature, sizeof(signature))) {
551  memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1);
552  signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb);
553  if (pb->eof_reached)
554  return AVERROR_EOF;
555  }
556  /* initialize private context members */
557  ipmovie->video_pts = ipmovie->audio_frame_count = 0;
558  ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset =
559  ipmovie->decode_map_chunk_offset = 0;
560 
561  /* on the first read, this will position the stream at the first chunk */
562  ipmovie->next_chunk_offset = avio_tell(pb) + 4;
563 
564  /* process the first chunk which should be CHUNK_INIT_VIDEO */
565  if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO)
566  return AVERROR_INVALIDDATA;
567 
568  /* peek ahead to the next chunk-- if it is an init audio chunk, process
569  * it; if it is the first video chunk, this is a silent file */
570  if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
572  return AVERROR(EIO);
573  chunk_type = AV_RL16(&chunk_preamble[2]);
574  avio_seek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR);
575 
576  if (chunk_type == CHUNK_VIDEO)
577  ipmovie->audio_type = CODEC_ID_NONE; /* no audio */
578  else if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO)
579  return AVERROR_INVALIDDATA;
580 
581  /* initialize the stream decoders */
582  st = avformat_new_stream(s, NULL);
583  if (!st)
584  return AVERROR(ENOMEM);
585  avpriv_set_pts_info(st, 63, 1, 1000000);
586  ipmovie->video_stream_index = st->index;
589  st->codec->codec_tag = 0; /* no fourcc */
590  st->codec->width = ipmovie->video_width;
591  st->codec->height = ipmovie->video_height;
592  st->codec->bits_per_coded_sample = ipmovie->video_bpp;
593 
594  if (ipmovie->audio_type) {
595  st = avformat_new_stream(s, NULL);
596  if (!st)
597  return AVERROR(ENOMEM);
598  avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate);
599  ipmovie->audio_stream_index = st->index;
601  st->codec->codec_id = ipmovie->audio_type;
602  st->codec->codec_tag = 0; /* no tag */
603  st->codec->channels = ipmovie->audio_channels;
604  st->codec->sample_rate = ipmovie->audio_sample_rate;
605  st->codec->bits_per_coded_sample = ipmovie->audio_bits;
606  st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
609  st->codec->bit_rate /= 2;
611  }
612 
613  return 0;
614 }
615 
617  AVPacket *pkt)
618 {
619  IPMVEContext *ipmovie = s->priv_data;
620  AVIOContext *pb = s->pb;
621  int ret;
622 
623  ret = process_ipmovie_chunk(ipmovie, pb, pkt);
624  if (ret == CHUNK_BAD)
625  ret = AVERROR_INVALIDDATA;
626  else if (ret == CHUNK_EOF)
627  ret = AVERROR(EIO);
628  else if (ret == CHUNK_NOMEM)
629  ret = AVERROR(ENOMEM);
630  else if (ret == CHUNK_VIDEO)
631  ret = 0;
632  else
633  ret = -1;
634 
635  return ret;
636 }
637 
639  .name = "ipmovie",
640  .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE format"),
641  .priv_data_size = sizeof(IPMVEContext),
645 };