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.

237 lines
6.4KB

  1. /*
  2. * Beam Software SIFF demuxer
  3. * Copyright (c) 2007 Konstantin Shishkov.
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg 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. * FFmpeg 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 FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avformat.h"
  22. enum SIFFTags{
  23. TAG_SIFF = MKTAG('S', 'I', 'F', 'F'),
  24. TAG_BODY = MKTAG('B', 'O', 'D', 'Y'),
  25. TAG_VBHD = MKTAG('V', 'B', 'H', 'D'),
  26. TAG_SHDR = MKTAG('S', 'H', 'D', 'R'),
  27. TAG_VBV1 = MKTAG('V', 'B', 'V', '1'),
  28. TAG_SOUN = MKTAG('S', 'O', 'U', 'N'),
  29. };
  30. enum VBFlags{
  31. VB_HAS_GMC = 0x01,
  32. VB_HAS_AUDIO = 0x04,
  33. VB_HAS_VIDEO = 0x08,
  34. VB_HAS_PALETTE = 0x10,
  35. VB_HAS_LENGTH = 0x20
  36. };
  37. typedef struct SIFFContext{
  38. int frames;
  39. int cur_frame;
  40. int rate;
  41. int bits;
  42. int block_align;
  43. int has_video;
  44. int has_audio;
  45. int curstrm;
  46. int pktsize;
  47. int gmcsize;
  48. int sndsize;
  49. int flags;
  50. uint8_t gmc[4];
  51. }SIFFContext;
  52. static int siff_probe(AVProbeData *p)
  53. {
  54. /* check file header */
  55. if (AV_RL32(p->buf) == TAG_SIFF)
  56. return AVPROBE_SCORE_MAX;
  57. else
  58. return 0;
  59. }
  60. static int create_audio_stream(AVFormatContext *s, SIFFContext *c)
  61. {
  62. AVStream *ast;
  63. ast = av_new_stream(s, 0);
  64. if (!ast)
  65. return -1;
  66. ast->codec->codec_type = CODEC_TYPE_AUDIO;
  67. ast->codec->codec_id = CODEC_ID_PCM_U8;
  68. ast->codec->channels = 1;
  69. ast->codec->bits_per_coded_sample = c->bits;
  70. ast->codec->sample_rate = c->rate;
  71. ast->codec->frame_size = c->block_align;
  72. av_set_pts_info(ast, 16, 1, c->rate);
  73. return 0;
  74. }
  75. static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
  76. {
  77. AVStream *st;
  78. int width, height;
  79. if (get_le32(pb) != TAG_VBHD){
  80. av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
  81. return -1;
  82. }
  83. if(get_be32(pb) != 32){
  84. av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
  85. return -1;
  86. }
  87. if(get_le16(pb) != 1){
  88. av_log(s, AV_LOG_ERROR, "Incorrect header version\n");
  89. return -1;
  90. }
  91. width = get_le16(pb);
  92. height = get_le16(pb);
  93. url_fskip(pb, 4);
  94. c->frames = get_le16(pb);
  95. if(!c->frames){
  96. av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
  97. return -1;
  98. }
  99. c->bits = get_le16(pb);
  100. c->rate = get_le16(pb);
  101. c->block_align = c->rate * (c->bits >> 3);
  102. url_fskip(pb, 16); //zeroes
  103. st = av_new_stream(s, 0);
  104. if (!st)
  105. return -1;
  106. st->codec->codec_type = CODEC_TYPE_VIDEO;
  107. st->codec->codec_id = CODEC_ID_VB;
  108. st->codec->codec_tag = MKTAG('V', 'B', 'V', '1');
  109. st->codec->width = width;
  110. st->codec->height = height;
  111. st->codec->pix_fmt = PIX_FMT_PAL8;
  112. av_set_pts_info(st, 16, 1, 12);
  113. c->cur_frame = 0;
  114. c->has_video = 1;
  115. c->has_audio = !!c->rate;
  116. c->curstrm = -1;
  117. if (c->has_audio && create_audio_stream(s, c) < 0)
  118. return -1;
  119. return 0;
  120. }
  121. static int siff_parse_soun(AVFormatContext *s, SIFFContext *c, ByteIOContext *pb)
  122. {
  123. if (get_le32(pb) != TAG_SHDR){
  124. av_log(s, AV_LOG_ERROR, "Header chunk is missing\n");
  125. return -1;
  126. }
  127. if(get_be32(pb) != 8){
  128. av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n");
  129. return -1;
  130. }
  131. url_fskip(pb, 4); //unknown value
  132. c->rate = get_le16(pb);
  133. c->bits = get_le16(pb);
  134. c->block_align = c->rate * (c->bits >> 3);
  135. return create_audio_stream(s, c);
  136. }
  137. static int siff_read_header(AVFormatContext *s, AVFormatParameters *ap)
  138. {
  139. ByteIOContext *pb = s->pb;
  140. SIFFContext *c = s->priv_data;
  141. uint32_t tag;
  142. if (get_le32(pb) != TAG_SIFF)
  143. return -1;
  144. url_fskip(pb, 4); //ignore size
  145. tag = get_le32(pb);
  146. if (tag != TAG_VBV1 && tag != TAG_SOUN){
  147. av_log(s, AV_LOG_ERROR, "Not a VBV file\n");
  148. return -1;
  149. }
  150. if (tag == TAG_VBV1 && siff_parse_vbv1(s, c, pb) < 0)
  151. return -1;
  152. if (tag == TAG_SOUN && siff_parse_soun(s, c, pb) < 0)
  153. return -1;
  154. if (get_le32(pb) != MKTAG('B', 'O', 'D', 'Y')){
  155. av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n");
  156. return -1;
  157. }
  158. url_fskip(pb, 4); //ignore size
  159. return 0;
  160. }
  161. static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
  162. {
  163. SIFFContext *c = s->priv_data;
  164. int size;
  165. if (c->has_video){
  166. if (c->cur_frame >= c->frames)
  167. return AVERROR(EIO);
  168. if (c->curstrm == -1){
  169. c->pktsize = get_le32(s->pb) - 4;
  170. c->flags = get_le16(s->pb);
  171. c->gmcsize = (c->flags & VB_HAS_GMC) ? 4 : 0;
  172. if (c->gmcsize)
  173. get_buffer(s->pb, c->gmc, c->gmcsize);
  174. c->sndsize = (c->flags & VB_HAS_AUDIO) ? get_le32(s->pb): 0;
  175. c->curstrm = !!(c->flags & VB_HAS_AUDIO);
  176. }
  177. if (!c->curstrm){
  178. size = c->pktsize - c->sndsize;
  179. if (av_new_packet(pkt, size) < 0)
  180. return AVERROR(ENOMEM);
  181. AV_WL16(pkt->data, c->flags);
  182. if (c->gmcsize)
  183. memcpy(pkt->data + 2, c->gmc, c->gmcsize);
  184. get_buffer(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2);
  185. pkt->stream_index = 0;
  186. c->curstrm = -1;
  187. }else{
  188. if (av_get_packet(s->pb, pkt, c->sndsize - 4) < 0)
  189. return AVERROR(EIO);
  190. pkt->stream_index = 1;
  191. c->curstrm = 0;
  192. }
  193. if(!c->cur_frame || c->curstrm)
  194. pkt->flags |= PKT_FLAG_KEY;
  195. if (c->curstrm == -1)
  196. c->cur_frame++;
  197. }else{
  198. size = av_get_packet(s->pb, pkt, c->block_align);
  199. if(size <= 0)
  200. return AVERROR(EIO);
  201. }
  202. return pkt->size;
  203. }
  204. AVInputFormat siff_demuxer = {
  205. "siff",
  206. NULL_IF_CONFIG_SMALL("Beam Software SIFF"),
  207. sizeof(SIFFContext),
  208. siff_probe,
  209. siff_read_header,
  210. siff_read_packet,
  211. .extensions = "vb,son"
  212. };