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 "libavutil/mem.h"
26 #include "libavcodec/mjpeg.h"
32 #define DEFAULT_PACKET_SIZE 1024
33 #define OVERREAD_SIZE 3
35 typedef struct MXGContext
{
39 unsigned int buffer_size
;
41 unsigned int cache_size
;
44 static int mxg_read_header(AVFormatContext
*s
)
46 AVStream
*video_st
, *audio_st
;
47 MXGContext
*mxg
= s
->priv_data
;
49 /* video parameters will be extracted from the compressed bitstream */
50 video_st
= avformat_new_stream(s
, NULL
);
52 return AVERROR(ENOMEM
);
53 video_st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
54 video_st
->codecpar
->codec_id
= AV_CODEC_ID_MXPEG
;
55 avpriv_set_pts_info(video_st
, 64, 1, 1000000);
57 audio_st
= avformat_new_stream(s
, NULL
);
59 return AVERROR(ENOMEM
);
60 audio_st
->codecpar
->codec_type
= AVMEDIA_TYPE_AUDIO
;
61 audio_st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_ALAW
;
62 audio_st
->codecpar
->ch_layout
= (AVChannelLayout
)AV_CHANNEL_LAYOUT_MONO
;
63 audio_st
->codecpar
->sample_rate
= 8000;
64 audio_st
->codecpar
->bits_per_coded_sample
= 8;
65 audio_st
->codecpar
->block_align
= 1;
66 avpriv_set_pts_info(audio_st
, 64, 1, 1000000);
68 mxg
->soi_ptr
= mxg
->buffer_ptr
= mxg
->buffer
= 0;
70 mxg
->dts
= AV_NOPTS_VALUE
;
76 static uint8_t* mxg_find_startmarker(uint8_t *p
, uint8_t *end
)
78 for (; p
< end
- 3; p
+= 4) {
79 uint32_t x
= AV_RN32(p
);
81 if (x
& (~(x
+0x01010101)) & 0x80808080) {
84 } else if (p
[1] == 0xff) {
86 } else if (p
[2] == 0xff) {
88 } else if (p
[3] == 0xff) {
94 for (; p
< end
; ++p
) {
95 if (*p
== 0xff) return p
;
101 static int mxg_update_cache(AVFormatContext
*s
, unsigned int cache_size
)
103 MXGContext
*mxg
= s
->priv_data
;
104 unsigned int current_pos
= mxg
->buffer_ptr
- mxg
->buffer
;
105 unsigned int soi_pos
;
109 /* reallocate internal buffer */
110 if (current_pos
> current_pos
+ cache_size
)
111 return AVERROR(ENOMEM
);
112 soi_pos
= mxg
->soi_ptr
- mxg
->buffer
;
113 buffer
= av_fast_realloc(mxg
->buffer
, &mxg
->buffer_size
,
114 current_pos
+ cache_size
+
115 AV_INPUT_BUFFER_PADDING_SIZE
);
117 return AVERROR(ENOMEM
);
118 mxg
->buffer
= buffer
;
119 mxg
->buffer_ptr
= mxg
->buffer
+ current_pos
;
120 if (mxg
->soi_ptr
) mxg
->soi_ptr
= mxg
->buffer
+ soi_pos
;
123 ret
= avio_read(s
->pb
, mxg
->buffer_ptr
+ mxg
->cache_size
,
124 cache_size
- mxg
->cache_size
);
128 mxg
->cache_size
+= ret
;
130 memset(mxg
->buffer_ptr
+ mxg
->cache_size
, 0, AV_INPUT_BUFFER_PADDING_SIZE
);
135 static int mxg_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
139 uint8_t *startmarker_ptr
, *end
, *search_end
, marker
;
140 MXGContext
*mxg
= s
->priv_data
;
142 while (!avio_feof(s
->pb
) && !s
->pb
->error
){
143 if (mxg
->cache_size
<= OVERREAD_SIZE
) {
144 /* update internal buffer */
145 ret
= mxg_update_cache(s
, DEFAULT_PACKET_SIZE
+ OVERREAD_SIZE
);
149 end
= mxg
->buffer_ptr
+ mxg
->cache_size
;
151 /* find start marker - 0xff */
152 if (mxg
->cache_size
> OVERREAD_SIZE
) {
153 search_end
= end
- OVERREAD_SIZE
;
154 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
157 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
158 if (startmarker_ptr
>= search_end
- 1 ||
159 *(startmarker_ptr
+ 1) != EOI
) break;
162 if (startmarker_ptr
!= search_end
) { /* start marker found */
163 marker
= *(startmarker_ptr
+ 1);
164 mxg
->buffer_ptr
= startmarker_ptr
+ 2;
165 mxg
->cache_size
= end
- mxg
->buffer_ptr
;
168 mxg
->soi_ptr
= startmarker_ptr
;
169 } else if (marker
== EOI
) {
171 av_log(s
, AV_LOG_WARNING
, "Found EOI before SOI, skipping\n");
175 size
= mxg
->buffer_ptr
- mxg
->soi_ptr
;
176 ret
= av_new_packet(pkt
, size
);
179 memcpy(pkt
->data
, mxg
->soi_ptr
, size
);
181 pkt
->pts
= pkt
->dts
= mxg
->dts
;
182 pkt
->stream_index
= 0;
184 if (mxg
->soi_ptr
- mxg
->buffer
> mxg
->cache_size
) {
185 if (mxg
->cache_size
> 0) {
186 memmove(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
189 mxg
->buffer_ptr
= mxg
->buffer
;
194 } else if ( (SOF0
<= marker
&& marker
<= SOF15
) ||
195 (SOS
<= marker
&& marker
<= COM
) ) {
196 /* all other markers that start marker segment also contain
197 length value (see specification for JPEG Annex B.1) */
198 size
= AV_RB16(mxg
->buffer_ptr
);
200 return AVERROR(EINVAL
);
202 if (mxg
->cache_size
< size
) {
203 ret
= mxg_update_cache(s
, size
);
206 startmarker_ptr
= mxg
->buffer_ptr
- 2;
209 mxg
->cache_size
-= size
;
212 mxg
->buffer_ptr
+= size
;
214 if (marker
== APP13
&& size
>= 16) { /* audio data */
215 ret
= av_new_packet(pkt
, size
- 14);
218 memcpy(pkt
->data
, startmarker_ptr
+ 16, size
- 14);
220 /* time (GMT) of first sample in usec since 1970, little-endian */
221 pkt
->pts
= pkt
->dts
= AV_RL64(startmarker_ptr
+ 8);
222 pkt
->stream_index
= 1;
224 if (startmarker_ptr
- mxg
->buffer
> mxg
->cache_size
) {
225 if (mxg
->cache_size
> 0) {
226 memcpy(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
228 mxg
->buffer_ptr
= mxg
->buffer
;
232 } else if (marker
== COM
&& size
>= 18 &&
233 !strncmp(startmarker_ptr
+ 4, "MXF", 3)) {
234 /* time (GMT) of video frame in usec since 1970, little-endian */
235 mxg
->dts
= AV_RL64(startmarker_ptr
+ 12);
239 /* start marker not found */
240 mxg
->buffer_ptr
= search_end
;
241 mxg
->cache_size
= OVERREAD_SIZE
;
248 static int mxg_close(struct AVFormatContext
*s
)
250 MXGContext
*mxg
= s
->priv_data
;
251 av_freep(&mxg
->buffer
);
255 const FFInputFormat ff_mxg_demuxer
= {
257 .p
.long_name
= NULL_IF_CONFIG_SMALL("MxPEG clip"),
258 .p
.extensions
= "mxg",
259 .priv_data_size
= sizeof(MXGContext
),
260 .read_header
= mxg_read_header
,
261 .read_packet
= mxg_read_packet
,
262 .read_close
= mxg_close
,