3 * Copyright (c) 2011 Paul B Mahol
5 * This file is part of FFmpeg.
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.
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.
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
24 * This is a demuxer for Loki SDL Motion JPEG files
34 typedef struct SMJPEGContext
{
35 int audio_stream_index
;
36 int video_stream_index
;
39 static int smjpeg_probe(AVProbeData
*p
)
41 if (!memcmp(p
->buf
, SMJPEG_MAGIC
, 8))
42 return AVPROBE_SCORE_MAX
;
46 static int smjpeg_read_header(AVFormatContext
*s
)
48 SMJPEGContext
*sc
= s
->priv_data
;
49 AVStream
*ast
= NULL
, *vst
= NULL
;
50 AVIOContext
*pb
= s
->pb
;
51 uint32_t version
, htype
, hlength
, duration
;
54 avio_skip(pb
, 8); // magic
55 version
= avio_rb32(pb
);
57 avpriv_request_sample(s
, "Unknown version %"PRIu32
, version
);
59 duration
= avio_rb32(pb
); // in msec
61 while (!avio_feof(pb
)) {
62 htype
= avio_rl32(pb
);
65 hlength
= avio_rb32(pb
);
66 if (!hlength
|| hlength
> 512)
67 return AVERROR_INVALIDDATA
;
68 comment
= av_malloc(hlength
+ 1);
70 return AVERROR(ENOMEM
);
71 if (avio_read(pb
, comment
, hlength
) != hlength
) {
73 av_log(s
, AV_LOG_ERROR
, "error when reading comment\n");
74 return AVERROR_INVALIDDATA
;
77 av_dict_set(&s
->metadata
, "comment", comment
,
78 AV_DICT_DONT_STRDUP_VAL
);
82 avpriv_request_sample(s
, "Multiple audio streams");
83 return AVERROR_PATCHWELCOME
;
85 hlength
= avio_rb32(pb
);
87 return AVERROR_INVALIDDATA
;
88 ast
= avformat_new_stream(s
, 0);
90 return AVERROR(ENOMEM
);
91 ast
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
92 ast
->codec
->sample_rate
= avio_rb16(pb
);
93 ast
->codec
->bits_per_coded_sample
= avio_r8(pb
);
94 ast
->codec
->channels
= avio_r8(pb
);
95 ast
->codec
->codec_tag
= avio_rl32(pb
);
96 ast
->codec
->codec_id
= ff_codec_get_id(ff_codec_smjpeg_audio_tags
,
97 ast
->codec
->codec_tag
);
98 ast
->duration
= duration
;
99 sc
->audio_stream_index
= ast
->index
;
100 avpriv_set_pts_info(ast
, 32, 1, 1000);
101 avio_skip(pb
, hlength
- 8);
105 avpriv_request_sample(s
, "Multiple video streams");
106 return AVERROR_INVALIDDATA
;
108 hlength
= avio_rb32(pb
);
110 return AVERROR_INVALIDDATA
;
111 vst
= avformat_new_stream(s
, 0);
113 return AVERROR(ENOMEM
);
114 vst
->nb_frames
= avio_rb32(pb
);
115 vst
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
116 vst
->codec
->width
= avio_rb16(pb
);
117 vst
->codec
->height
= avio_rb16(pb
);
118 vst
->codec
->codec_tag
= avio_rl32(pb
);
119 vst
->codec
->codec_id
= ff_codec_get_id(ff_codec_smjpeg_video_tags
,
120 vst
->codec
->codec_tag
);
121 vst
->duration
= duration
;
122 sc
->video_stream_index
= vst
->index
;
123 avpriv_set_pts_info(vst
, 32, 1, 1000);
124 avio_skip(pb
, hlength
- 12);
129 av_log(s
, AV_LOG_ERROR
, "unknown header %"PRIx32
"\n", htype
);
130 return AVERROR_INVALIDDATA
;
137 static int smjpeg_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
139 SMJPEGContext
*sc
= s
->priv_data
;
140 uint32_t dtype
, size
, timestamp
;
144 if (avio_feof(s
->pb
))
146 pos
= avio_tell(s
->pb
);
147 dtype
= avio_rl32(s
->pb
);
150 timestamp
= avio_rb32(s
->pb
);
151 size
= avio_rb32(s
->pb
);
152 ret
= av_get_packet(s
->pb
, pkt
, size
);
153 pkt
->stream_index
= sc
->audio_stream_index
;
154 pkt
->pts
= timestamp
;
158 timestamp
= avio_rb32(s
->pb
);
159 size
= avio_rb32(s
->pb
);
160 ret
= av_get_packet(s
->pb
, pkt
, size
);
161 pkt
->stream_index
= sc
->video_stream_index
;
162 pkt
->pts
= timestamp
;
169 av_log(s
, AV_LOG_ERROR
, "unknown chunk %"PRIx32
"\n", dtype
);
170 ret
= AVERROR_INVALIDDATA
;
176 AVInputFormat ff_smjpeg_demuxer
= {
178 .long_name
= NULL_IF_CONFIG_SMALL("Loki SDL MJPEG"),
179 .priv_data_size
= sizeof(SMJPEGContext
),
180 .read_probe
= smjpeg_probe
,
181 .read_header
= smjpeg_read_header
,
182 .read_packet
= smjpeg_read_packet
,
183 .extensions
= "mjpg",
184 .flags
= AVFMT_GENERIC_INDEX
,