You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
10KB

  1. /*
  2. * Sierra VMD Format Demuxer
  3. * Copyright (c) 2004 The ffmpeg Project
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. /**
  20. * @file sierravmd.c
  21. * Sierra VMD file demuxer
  22. * by Vladimir "VAG" Gneushev (vagsoft at mail.ru)
  23. * for more information on the Sierra VMD file format, visit:
  24. * http://www.pcisys.net/~melanson/codecs/
  25. */
  26. #include "avformat.h"
  27. #define VMD_HEADER_SIZE 0x0330
  28. #define BYTES_PER_FRAME_RECORD 16
  29. typedef struct {
  30. int stream_index;
  31. offset_t frame_offset;
  32. unsigned int frame_size;
  33. int64_t pts;
  34. int keyframe;
  35. unsigned char frame_record[BYTES_PER_FRAME_RECORD];
  36. } vmd_frame_t;
  37. typedef struct VmdDemuxContext {
  38. int video_stream_index;
  39. int audio_stream_index;
  40. unsigned int audio_type;
  41. unsigned int audio_samplerate;
  42. unsigned int audio_bits;
  43. unsigned int audio_channels;
  44. unsigned int frame_count;
  45. vmd_frame_t *frame_table;
  46. unsigned int current_frame;
  47. int sample_rate;
  48. int64_t audio_sample_counter;
  49. int audio_frame_divisor;
  50. int audio_block_align;
  51. unsigned char vmd_header[VMD_HEADER_SIZE];
  52. } VmdDemuxContext;
  53. static int vmd_probe(AVProbeData *p)
  54. {
  55. if (p->buf_size < 2)
  56. return 0;
  57. /* check if the first 2 bytes of the file contain the appropriate size
  58. * of a VMD header chunk */
  59. if (LE_16(&p->buf[0]) != VMD_HEADER_SIZE - 2)
  60. return 0;
  61. /* only return half certainty since this check is a bit sketchy */
  62. return AVPROBE_SCORE_MAX / 2;
  63. }
  64. /* This is a support function to determine the duration, in sample
  65. * frames, of a particular audio chunk, taking into account silent
  66. * encodings. */
  67. static int vmd_calculate_audio_duration(unsigned char *audio_chunk,
  68. int audio_chunk_size, int block_align)
  69. {
  70. unsigned char *p = audio_chunk + 16;
  71. unsigned char *p_end = audio_chunk + audio_chunk_size;
  72. int total_samples = 0;
  73. unsigned int sound_flags;
  74. if (audio_chunk_size < 16)
  75. return 0;
  76. sound_flags = LE_32(p);
  77. p += 4;
  78. while (p < p_end) {
  79. total_samples += block_align;
  80. if ((sound_flags & 0x01) == 0)
  81. p += block_align;
  82. sound_flags >>= 1;
  83. }
  84. return total_samples;
  85. }
  86. static int vmd_read_header(AVFormatContext *s,
  87. AVFormatParameters *ap)
  88. {
  89. VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
  90. ByteIOContext *pb = &s->pb;
  91. AVStream *st;
  92. unsigned int toc_offset;
  93. unsigned char *raw_frame_table;
  94. int raw_frame_table_size;
  95. unsigned char *current_frame_record;
  96. offset_t current_offset;
  97. int i;
  98. unsigned int total_frames;
  99. int64_t video_pts_inc;
  100. int64_t current_video_pts = 0;
  101. /* fetch the main header, including the 2 header length bytes */
  102. url_fseek(pb, 0, SEEK_SET);
  103. if (get_buffer(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
  104. return -EIO;
  105. vmd->audio_sample_counter = 0;
  106. vmd->audio_frame_divisor = 1;
  107. vmd->audio_block_align = 1;
  108. /* start up the decoders */
  109. st = av_new_stream(s, 0);
  110. if (!st)
  111. return AVERROR_NOMEM;
  112. vmd->video_stream_index = st->index;
  113. st->codec.codec_type = CODEC_TYPE_VIDEO;
  114. st->codec.codec_id = CODEC_ID_VMDVIDEO;
  115. st->codec.codec_tag = 0; /* no fourcc */
  116. st->codec.width = LE_16(&vmd->vmd_header[12]);
  117. st->codec.height = LE_16(&vmd->vmd_header[14]);
  118. st->codec.extradata_size = VMD_HEADER_SIZE;
  119. st->codec.extradata = av_malloc(VMD_HEADER_SIZE);
  120. memcpy(st->codec.extradata, vmd->vmd_header, VMD_HEADER_SIZE);
  121. /* if sample rate is 0, assume no audio */
  122. vmd->sample_rate = LE_16(&vmd->vmd_header[804]);
  123. if (vmd->sample_rate) {
  124. st = av_new_stream(s, 0);
  125. if (!st)
  126. return AVERROR_NOMEM;
  127. vmd->audio_stream_index = st->index;
  128. st->codec.codec_type = CODEC_TYPE_AUDIO;
  129. st->codec.codec_id = CODEC_ID_VMDAUDIO;
  130. st->codec.codec_tag = 0; /* no codec tag */
  131. st->codec.channels = (vmd->vmd_header[811] & 0x80) ? 2 : 1;
  132. st->codec.sample_rate = vmd->sample_rate;
  133. st->codec.block_align = vmd->audio_block_align =
  134. LE_16(&vmd->vmd_header[806]);
  135. if (st->codec.block_align & 0x8000) {
  136. st->codec.bits_per_sample = 16;
  137. st->codec.block_align = -(st->codec.block_align - 0x10000);
  138. } else
  139. st->codec.bits_per_sample = 16;
  140. // st->codec.bits_per_sample = 8;
  141. st->codec.bit_rate = st->codec.sample_rate *
  142. st->codec.bits_per_sample * st->codec.channels;
  143. /* for calculating pts */
  144. vmd->audio_frame_divisor = st->codec.bits_per_sample / 8 /
  145. st->codec.channels;
  146. video_pts_inc = 90000;
  147. video_pts_inc *= st->codec.block_align;
  148. video_pts_inc /= st->codec.sample_rate;
  149. } else {
  150. /* if no audio, assume 10 frames/second */
  151. video_pts_inc = 90000 / 10;
  152. }
  153. /* skip over the offset table and load the table of contents; don't
  154. * care about the offset table since demuxer will calculate those
  155. * independently */
  156. toc_offset = LE_32(&vmd->vmd_header[812]);
  157. vmd->frame_count = LE_16(&vmd->vmd_header[6]);
  158. url_fseek(pb, toc_offset + vmd->frame_count * 6, SEEK_SET);
  159. /* each on-disk VMD frame has an audio part and a video part; demuxer
  160. * accounts them separately */
  161. vmd->frame_count *= 2;
  162. raw_frame_table = NULL;
  163. vmd->frame_table = NULL;
  164. raw_frame_table_size = vmd->frame_count * BYTES_PER_FRAME_RECORD;
  165. raw_frame_table = av_malloc(raw_frame_table_size);
  166. vmd->frame_table = av_malloc(vmd->frame_count * sizeof(vmd_frame_t));
  167. if (!raw_frame_table || !vmd->frame_table) {
  168. av_free(raw_frame_table);
  169. av_free(vmd->frame_table);
  170. return AVERROR_NOMEM;
  171. }
  172. if (get_buffer(pb, raw_frame_table, raw_frame_table_size) !=
  173. raw_frame_table_size) {
  174. av_free(raw_frame_table);
  175. av_free(vmd->frame_table);
  176. return -EIO;
  177. }
  178. current_offset = LE_32(&vmd->vmd_header[20]);
  179. current_frame_record = raw_frame_table;
  180. total_frames = vmd->frame_count;
  181. i = 0;
  182. while (total_frames--) {
  183. /* if the frame size is 0, do not count the frame and bring the
  184. * total frame count down */
  185. vmd->frame_table[i].frame_size = LE_32(&current_frame_record[2]);
  186. /* this logic is present so that 0-length audio chunks are not
  187. * accounted */
  188. if (!vmd->frame_table[i].frame_size) {
  189. vmd->frame_count--; /* one less frame to count */
  190. current_frame_record += BYTES_PER_FRAME_RECORD;
  191. continue;
  192. }
  193. if (current_frame_record[0] == 0x02)
  194. vmd->frame_table[i].stream_index = vmd->video_stream_index;
  195. else
  196. vmd->frame_table[i].stream_index = vmd->audio_stream_index;
  197. vmd->frame_table[i].frame_offset = current_offset;
  198. current_offset += vmd->frame_table[i].frame_size;
  199. memcpy(vmd->frame_table[i].frame_record, current_frame_record,
  200. BYTES_PER_FRAME_RECORD);
  201. /* figure out the pts for this frame */
  202. if (current_frame_record[0] == 0x02) {
  203. vmd->frame_table[i].pts = current_video_pts;
  204. current_video_pts += video_pts_inc;
  205. } else if (current_frame_record[0] == 0x01) {
  206. /* figure out the pts during the dispatch phase */
  207. vmd->frame_table[i].pts = 0;
  208. }
  209. current_frame_record += BYTES_PER_FRAME_RECORD;
  210. i++;
  211. }
  212. av_free(raw_frame_table);
  213. /* set the pts reference at 1 pts = 1/90000 sec */
  214. s->pts_num = 1;
  215. s->pts_den = 90000;
  216. vmd->current_frame = 0;
  217. return 0;
  218. }
  219. static int vmd_read_packet(AVFormatContext *s,
  220. AVPacket *pkt)
  221. {
  222. VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
  223. ByteIOContext *pb = &s->pb;
  224. int ret = 0;
  225. vmd_frame_t *frame;
  226. if (vmd->current_frame >= vmd->frame_count)
  227. return -EIO;
  228. frame = &vmd->frame_table[vmd->current_frame];
  229. /* position the stream (will probably be there already) */
  230. url_fseek(pb, frame->frame_offset, SEEK_SET);
  231. if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD))
  232. return AVERROR_NOMEM;
  233. memcpy(pkt->data, frame->frame_record, BYTES_PER_FRAME_RECORD);
  234. ret = get_buffer(pb, pkt->data + BYTES_PER_FRAME_RECORD,
  235. frame->frame_size);
  236. if (ret != frame->frame_size) {
  237. av_free_packet(pkt);
  238. ret = -EIO;
  239. }
  240. pkt->stream_index = frame->stream_index;
  241. if (frame->frame_record[0] == 0x02)
  242. pkt->pts = frame->pts;
  243. else {
  244. pkt->pts = vmd->audio_sample_counter;
  245. pkt->pts *= 90000;
  246. pkt->pts /= vmd->sample_rate;
  247. // pkt->pts /= vmd->audio_frame_divisor;
  248. vmd->audio_sample_counter += vmd_calculate_audio_duration(
  249. pkt->data, pkt->size, vmd->audio_block_align);
  250. }
  251. printf (" dispatching %s frame with %d bytes and pts %lld (%0.1f sec)\n",
  252. (frame->frame_record[0] == 0x02) ? "video" : "audio",
  253. frame->frame_size + BYTES_PER_FRAME_RECORD,
  254. pkt->pts, (float)(pkt->pts / 90000.0));
  255. vmd->current_frame++;
  256. return ret;
  257. }
  258. static int vmd_read_close(AVFormatContext *s)
  259. {
  260. VmdDemuxContext *vmd = (VmdDemuxContext *)s->priv_data;
  261. av_free(vmd->frame_table);
  262. return 0;
  263. }
  264. static AVInputFormat vmd_iformat = {
  265. "vmd",
  266. "Sierra VMD format",
  267. sizeof(VmdDemuxContext),
  268. vmd_probe,
  269. vmd_read_header,
  270. vmd_read_packet,
  271. vmd_read_close,
  272. };
  273. int vmd_init(void)
  274. {
  275. av_register_input_format(&vmd_iformat);
  276. return 0;
  277. }