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.

184 lines
6.1KB

  1. /*
  2. * SMJPEG demuxer
  3. * Copyright (c) 2011 Paul B Mahol
  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. /**
  22. * @file
  23. * This is a demuxer for Loki SDL MJPEG files
  24. */
  25. #include "avformat.h"
  26. #include "internal.h"
  27. #include "riff.h"
  28. static const AVCodecTag codec_smjpeg_tags[] = {
  29. { CODEC_ID_ADPCM_IMA_SMJPEG, MKTAG('A', 'P', 'C', 'M') },
  30. { CODEC_ID_PCM_S16LE, MKTAG('N', 'O', 'N', 'E') },
  31. { CODEC_ID_MJPEG, MKTAG('J', 'F', 'I', 'F') },
  32. { CODEC_ID_NONE, 0 },
  33. };
  34. typedef struct SMJPEGContext {
  35. int audio_stream_index;
  36. int video_stream_index;
  37. } SMJPEGContext;
  38. static int smjpeg_probe(AVProbeData *p)
  39. {
  40. if (!memcmp(p->buf, "\x0\xaSMJPEG", 8))
  41. return AVPROBE_SCORE_MAX;
  42. return 0;
  43. }
  44. static int smjpeg_read_header(AVFormatContext *s, AVFormatParameters *ap)
  45. {
  46. SMJPEGContext *sc = s->priv_data;
  47. AVStream *ast = NULL, *vst = NULL;
  48. AVIOContext *pb = s->pb;
  49. uint32_t version, htype, hlength, duration;
  50. char *comment;
  51. avio_skip(pb, 8); // magic
  52. version = avio_rb32(pb);
  53. if (version) {
  54. av_log_ask_for_sample(s, "unknown version %d\n", version);
  55. }
  56. duration = avio_rb32(pb); // in msec
  57. while (!pb->eof_reached) {
  58. htype = avio_rl32(pb);
  59. switch (htype) {
  60. case MKTAG('_', 'T', 'X', 'T'):
  61. hlength = avio_rb32(pb);
  62. if (!hlength || hlength > 512)
  63. return AVERROR_INVALIDDATA;
  64. comment = av_malloc(hlength + 1);
  65. if (!comment)
  66. return AVERROR(ENOMEM);
  67. if (avio_read(pb, comment, hlength) != hlength) {
  68. av_freep(&comment);
  69. av_log(s, AV_LOG_ERROR, "error when reading comment\n");
  70. return AVERROR_INVALIDDATA;
  71. }
  72. comment[hlength] = 0;
  73. av_dict_set(&s->metadata, "comment", comment,
  74. AV_DICT_DONT_STRDUP_VAL);
  75. break;
  76. case MKTAG('_', 'S', 'N', 'D'):
  77. if (ast) {
  78. av_log_ask_for_sample(s, "multiple audio streams not supported\n");
  79. return AVERROR_INVALIDDATA;
  80. }
  81. hlength = avio_rb32(pb);
  82. if (hlength < 8)
  83. return AVERROR_INVALIDDATA;
  84. ast = avformat_new_stream(s, 0);
  85. if (!ast)
  86. return AVERROR(ENOMEM);
  87. ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
  88. ast->codec->sample_rate = avio_rb16(pb);
  89. ast->codec->bits_per_coded_sample = avio_r8(pb);
  90. ast->codec->channels = avio_r8(pb);
  91. ast->codec->codec_tag = avio_rl32(pb);
  92. ast->codec->codec_id = ff_codec_get_id(codec_smjpeg_tags,
  93. ast->codec->codec_tag);
  94. ast->duration = duration;
  95. sc->audio_stream_index = ast->index;
  96. avpriv_set_pts_info(ast, 32, 1, 1000);
  97. avio_skip(pb, hlength - 8);
  98. break;
  99. case MKTAG('_', 'V', 'I', 'D'):
  100. if (vst) {
  101. av_log_ask_for_sample(s, "multiple video streams not supported\n");
  102. return AVERROR_INVALIDDATA;
  103. }
  104. hlength = avio_rb32(pb);
  105. if (hlength < 12)
  106. return AVERROR_INVALIDDATA;
  107. avio_skip(pb, 4); // number of frames
  108. vst = avformat_new_stream(s, 0);
  109. if (!vst)
  110. return AVERROR(ENOMEM);
  111. vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
  112. vst->codec->width = avio_rb16(pb);
  113. vst->codec->height = avio_rb16(pb);
  114. vst->codec->codec_tag = avio_rl32(pb);
  115. vst->codec->codec_id = ff_codec_get_id(codec_smjpeg_tags,
  116. vst->codec->codec_tag);
  117. vst->duration = duration;
  118. sc->video_stream_index = vst->index;
  119. avpriv_set_pts_info(vst, 32, 1, 1000);
  120. avio_skip(pb, hlength - 12);
  121. break;
  122. case MKTAG('H', 'E', 'N', 'D'):
  123. return 0;
  124. default:
  125. av_log(s, AV_LOG_ERROR, "unknown header %x\n", htype);
  126. return AVERROR_INVALIDDATA;
  127. }
  128. }
  129. return AVERROR_EOF;
  130. }
  131. static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
  132. {
  133. SMJPEGContext *sc = s->priv_data;
  134. uint32_t dtype, ret, size, timestamp;
  135. if (s->pb->eof_reached)
  136. return AVERROR_EOF;
  137. dtype = avio_rl32(s->pb);
  138. switch (dtype) {
  139. case MKTAG('s', 'n', 'd', 'D'):
  140. timestamp = avio_rb32(s->pb);
  141. size = avio_rb32(s->pb);
  142. ret = av_get_packet(s->pb, pkt, size);
  143. pkt->stream_index = sc->audio_stream_index;
  144. pkt->pts = timestamp;
  145. break;
  146. case MKTAG('v', 'i', 'd', 'D'):
  147. timestamp = avio_rb32(s->pb);
  148. size = avio_rb32(s->pb);
  149. ret = av_get_packet(s->pb, pkt, size);
  150. pkt->stream_index = sc->video_stream_index;
  151. pkt->pts = timestamp;
  152. break;
  153. case MKTAG('D', 'O', 'N', 'E'):
  154. ret = AVERROR_EOF;
  155. break;
  156. default:
  157. av_log(s, AV_LOG_ERROR, "unknown chunk %x\n", dtype);
  158. ret = AVERROR_INVALIDDATA;
  159. break;
  160. }
  161. return ret;
  162. }
  163. AVInputFormat ff_smjpeg_demuxer = {
  164. .name = "smjpeg",
  165. .long_name = NULL_IF_CONFIG_SMALL("Loki SDL MJPEG"),
  166. .priv_data_size = sizeof(SMJPEGContext),
  167. .read_probe = smjpeg_probe,
  168. .read_header = smjpeg_read_header,
  169. .read_packet = smjpeg_read_packet,
  170. .extensions = "mjpg",
  171. };