2 * MxPEG clip file demuxer
3 * Copyright (c) 2010 Anatoly Nenashev
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
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/internal.h"
24 #include "libavutil/intreadwrite.h"
25 #include "libavcodec/mjpeg.h"
30 #define DEFAULT_PACKET_SIZE 1024
31 #define OVERREAD_SIZE 3
33 typedef struct MXGContext
{
37 unsigned int buffer_size
;
39 unsigned int cache_size
;
42 static int mxg_read_header(AVFormatContext
*s
)
44 AVStream
*video_st
, *audio_st
;
45 MXGContext
*mxg
= s
->priv_data
;
47 /* video parameters will be extracted from the compressed bitstream */
48 video_st
= avformat_new_stream(s
, NULL
);
50 return AVERROR(ENOMEM
);
51 video_st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
52 video_st
->codec
->codec_id
= AV_CODEC_ID_MXPEG
;
53 avpriv_set_pts_info(video_st
, 64, 1, 1000000);
55 audio_st
= avformat_new_stream(s
, NULL
);
57 return AVERROR(ENOMEM
);
58 audio_st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
59 audio_st
->codec
->codec_id
= AV_CODEC_ID_PCM_ALAW
;
60 audio_st
->codec
->channels
= 1;
61 audio_st
->codec
->channel_layout
= AV_CH_LAYOUT_MONO
;
62 audio_st
->codec
->sample_rate
= 8000;
63 audio_st
->codec
->bits_per_coded_sample
= 8;
64 audio_st
->codec
->block_align
= 1;
65 avpriv_set_pts_info(audio_st
, 64, 1, 1000000);
67 mxg
->soi_ptr
= mxg
->buffer_ptr
= mxg
->buffer
= 0;
69 mxg
->dts
= AV_NOPTS_VALUE
;
75 static uint8_t* mxg_find_startmarker(uint8_t *p
, uint8_t *end
)
77 for (; p
< end
- 3; p
+= 4) {
78 uint32_t x
= AV_RN32(p
);
80 if (x
& (~(x
+0x01010101)) & 0x80808080) {
83 } else if (p
[1] == 0xff) {
85 } else if (p
[2] == 0xff) {
87 } else if (p
[3] == 0xff) {
93 for (; p
< end
; ++p
) {
94 if (*p
== 0xff) return p
;
100 static int mxg_update_cache(AVFormatContext
*s
, unsigned int cache_size
)
102 MXGContext
*mxg
= s
->priv_data
;
103 unsigned int current_pos
= mxg
->buffer_ptr
- mxg
->buffer
;
104 unsigned int soi_pos
;
108 /* reallocate internal buffer */
109 if (current_pos
> current_pos
+ cache_size
)
110 return AVERROR(ENOMEM
);
111 soi_pos
= mxg
->soi_ptr
- mxg
->buffer
;
112 buffer
= av_fast_realloc(mxg
->buffer
, &mxg
->buffer_size
,
113 current_pos
+ cache_size
+
114 FF_INPUT_BUFFER_PADDING_SIZE
);
116 return AVERROR(ENOMEM
);
117 mxg
->buffer
= buffer
;
118 mxg
->buffer_ptr
= mxg
->buffer
+ current_pos
;
119 if (mxg
->soi_ptr
) mxg
->soi_ptr
= mxg
->buffer
+ soi_pos
;
122 ret
= avio_read(s
->pb
, mxg
->buffer_ptr
+ mxg
->cache_size
,
123 cache_size
- mxg
->cache_size
);
127 mxg
->cache_size
+= ret
;
132 static int mxg_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
136 uint8_t *startmarker_ptr
, *end
, *search_end
, marker
;
137 MXGContext
*mxg
= s
->priv_data
;
139 while (!avio_feof(s
->pb
) && !s
->pb
->error
){
140 if (mxg
->cache_size
<= OVERREAD_SIZE
) {
141 /* update internal buffer */
142 ret
= mxg_update_cache(s
, DEFAULT_PACKET_SIZE
+ OVERREAD_SIZE
);
146 end
= mxg
->buffer_ptr
+ mxg
->cache_size
;
148 /* find start marker - 0xff */
149 if (mxg
->cache_size
> OVERREAD_SIZE
) {
150 search_end
= end
- OVERREAD_SIZE
;
151 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
154 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
155 if (startmarker_ptr
>= search_end
- 1 ||
156 *(startmarker_ptr
+ 1) != EOI
) break;
159 if (startmarker_ptr
!= search_end
) { /* start marker found */
160 marker
= *(startmarker_ptr
+ 1);
161 mxg
->buffer_ptr
= startmarker_ptr
+ 2;
162 mxg
->cache_size
= end
- mxg
->buffer_ptr
;
165 mxg
->soi_ptr
= startmarker_ptr
;
166 } else if (marker
== EOI
) {
168 av_log(s
, AV_LOG_WARNING
, "Found EOI before SOI, skipping\n");
172 pkt
->pts
= pkt
->dts
= mxg
->dts
;
173 pkt
->stream_index
= 0;
174 #if FF_API_DESTRUCT_PACKET
175 FF_DISABLE_DEPRECATION_WARNINGS
176 pkt
->destruct
= NULL
;
177 FF_ENABLE_DEPRECATION_WARNINGS
180 pkt
->size
= mxg
->buffer_ptr
- mxg
->soi_ptr
;
181 pkt
->data
= mxg
->soi_ptr
;
183 if (mxg
->soi_ptr
- mxg
->buffer
> mxg
->cache_size
) {
184 if (mxg
->cache_size
> 0) {
185 memcpy(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
188 mxg
->buffer_ptr
= mxg
->buffer
;
193 } else if ( (SOF0
<= marker
&& marker
<= SOF15
) ||
194 (SOS
<= marker
&& marker
<= COM
) ) {
195 /* all other markers that start marker segment also contain
196 length value (see specification for JPEG Annex B.1) */
197 size
= AV_RB16(mxg
->buffer_ptr
);
199 return AVERROR(EINVAL
);
201 if (mxg
->cache_size
< size
) {
202 ret
= mxg_update_cache(s
, size
);
205 startmarker_ptr
= mxg
->buffer_ptr
- 2;
208 mxg
->cache_size
-= size
;
211 mxg
->buffer_ptr
+= size
;
213 if (marker
== APP13
&& size
>= 16) { /* audio data */
214 /* time (GMT) of first sample in usec since 1970, little-endian */
215 pkt
->pts
= pkt
->dts
= AV_RL64(startmarker_ptr
+ 8);
216 pkt
->stream_index
= 1;
217 #if FF_API_DESTRUCT_PACKET
218 FF_DISABLE_DEPRECATION_WARNINGS
219 pkt
->destruct
= NULL
;
220 FF_ENABLE_DEPRECATION_WARNINGS
223 pkt
->size
= size
- 14;
224 pkt
->data
= startmarker_ptr
+ 16;
226 if (startmarker_ptr
- mxg
->buffer
> mxg
->cache_size
) {
227 if (mxg
->cache_size
> 0) {
228 memcpy(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
230 mxg
->buffer_ptr
= mxg
->buffer
;
234 } else if (marker
== COM
&& size
>= 18 &&
235 !strncmp(startmarker_ptr
+ 4, "MXF", 3)) {
236 /* time (GMT) of video frame in usec since 1970, little-endian */
237 mxg
->dts
= AV_RL64(startmarker_ptr
+ 12);
241 /* start marker not found */
242 mxg
->buffer_ptr
= search_end
;
243 mxg
->cache_size
= OVERREAD_SIZE
;
250 static int mxg_close(struct AVFormatContext
*s
)
252 MXGContext
*mxg
= s
->priv_data
;
253 av_freep(&mxg
->buffer
);
257 AVInputFormat ff_mxg_demuxer
= {
259 .long_name
= NULL_IF_CONFIG_SMALL("MxPEG clip"),
260 .priv_data_size
= sizeof(MXGContext
),
261 .read_header
= mxg_read_header
,
262 .read_packet
= mxg_read_packet
,
263 .read_close
= mxg_close
,