2 * MxPEG clip file demuxer
3 * Copyright (c) 2010 Anatoly Nenashev
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; 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/intreadwrite.h"
24 #include "libavcodec/mjpeg.h"
29 #define DEFAULT_PACKET_SIZE 1024
30 #define OVERREAD_SIZE 3
32 typedef struct MXGContext
{
36 unsigned int buffer_size
;
38 unsigned int cache_size
;
41 static int mxg_read_header(AVFormatContext
*s
)
43 AVStream
*video_st
, *audio_st
;
44 MXGContext
*mxg
= s
->priv_data
;
46 /* video parameters will be extracted from the compressed bitstream */
47 video_st
= avformat_new_stream(s
, NULL
);
49 return AVERROR(ENOMEM
);
50 video_st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
51 video_st
->codec
->codec_id
= AV_CODEC_ID_MXPEG
;
52 avpriv_set_pts_info(video_st
, 64, 1, 1000000);
54 audio_st
= avformat_new_stream(s
, NULL
);
56 return AVERROR(ENOMEM
);
57 audio_st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
58 audio_st
->codec
->codec_id
= AV_CODEC_ID_PCM_ALAW
;
59 audio_st
->codec
->channels
= 1;
60 audio_st
->codec
->channel_layout
= AV_CH_LAYOUT_MONO
;
61 audio_st
->codec
->sample_rate
= 8000;
62 audio_st
->codec
->bits_per_coded_sample
= 8;
63 audio_st
->codec
->block_align
= 1;
64 avpriv_set_pts_info(audio_st
, 64, 1, 1000000);
66 mxg
->soi_ptr
= mxg
->buffer_ptr
= mxg
->buffer
= 0;
68 mxg
->dts
= AV_NOPTS_VALUE
;
74 static uint8_t* mxg_find_startmarker(uint8_t *p
, uint8_t *end
)
76 for (; p
< end
- 3; p
+= 4) {
77 uint32_t x
= *(uint32_t*)p
;
79 if (x
& (~(x
+0x01010101)) & 0x80808080) {
82 } else if (p
[1] == 0xff) {
84 } else if (p
[2] == 0xff) {
86 } else if (p
[3] == 0xff) {
92 for (; p
< end
; ++p
) {
93 if (*p
== 0xff) return p
;
99 static int mxg_update_cache(AVFormatContext
*s
, unsigned int cache_size
)
101 MXGContext
*mxg
= s
->priv_data
;
102 unsigned int current_pos
= mxg
->buffer_ptr
- mxg
->buffer
;
103 unsigned int soi_pos
;
106 /* reallocate internal buffer */
107 if (current_pos
> current_pos
+ cache_size
)
108 return AVERROR(ENOMEM
);
109 if (mxg
->soi_ptr
) soi_pos
= mxg
->soi_ptr
- mxg
->buffer
;
110 mxg
->buffer
= av_fast_realloc(mxg
->buffer
, &mxg
->buffer_size
,
111 current_pos
+ cache_size
+
112 FF_INPUT_BUFFER_PADDING_SIZE
);
114 return AVERROR(ENOMEM
);
115 mxg
->buffer_ptr
= mxg
->buffer
+ current_pos
;
116 if (mxg
->soi_ptr
) mxg
->soi_ptr
= mxg
->buffer
+ soi_pos
;
119 ret
= avio_read(s
->pb
, mxg
->buffer_ptr
+ mxg
->cache_size
,
120 cache_size
- mxg
->cache_size
);
124 mxg
->cache_size
+= ret
;
129 static int mxg_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
133 uint8_t *startmarker_ptr
, *end
, *search_end
, marker
;
134 MXGContext
*mxg
= s
->priv_data
;
136 while (!s
->pb
->eof_reached
&& !s
->pb
->error
){
137 if (mxg
->cache_size
<= OVERREAD_SIZE
) {
138 /* update internal buffer */
139 ret
= mxg_update_cache(s
, DEFAULT_PACKET_SIZE
+ OVERREAD_SIZE
);
143 end
= mxg
->buffer_ptr
+ mxg
->cache_size
;
145 /* find start marker - 0xff */
146 if (mxg
->cache_size
> OVERREAD_SIZE
) {
147 search_end
= end
- OVERREAD_SIZE
;
148 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
151 startmarker_ptr
= mxg_find_startmarker(mxg
->buffer_ptr
, search_end
);
152 if (startmarker_ptr
>= search_end
- 1 ||
153 *(startmarker_ptr
+ 1) != EOI
) break;
156 if (startmarker_ptr
!= search_end
) { /* start marker found */
157 marker
= *(startmarker_ptr
+ 1);
158 mxg
->buffer_ptr
= startmarker_ptr
+ 2;
159 mxg
->cache_size
= end
- mxg
->buffer_ptr
;
162 mxg
->soi_ptr
= startmarker_ptr
;
163 } else if (marker
== EOI
) {
165 av_log(s
, AV_LOG_WARNING
, "Found EOI before SOI, skipping\n");
169 pkt
->pts
= pkt
->dts
= mxg
->dts
;
170 pkt
->stream_index
= 0;
171 #if FF_API_DESTRUCT_PACKET
172 pkt
->destruct
= NULL
;
175 pkt
->size
= mxg
->buffer_ptr
- mxg
->soi_ptr
;
176 pkt
->data
= mxg
->soi_ptr
;
178 if (mxg
->soi_ptr
- mxg
->buffer
> mxg
->cache_size
) {
179 if (mxg
->cache_size
> 0) {
180 memcpy(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
183 mxg
->buffer_ptr
= mxg
->buffer
;
188 } else if ( (SOF0
<= marker
&& marker
<= SOF15
) ||
189 (SOS
<= marker
&& marker
<= COM
) ) {
190 /* all other markers that start marker segment also contain
191 length value (see specification for JPEG Annex B.1) */
192 size
= AV_RB16(mxg
->buffer_ptr
);
194 return AVERROR(EINVAL
);
196 if (mxg
->cache_size
< size
) {
197 ret
= mxg_update_cache(s
, size
);
200 startmarker_ptr
= mxg
->buffer_ptr
- 2;
203 mxg
->cache_size
-= size
;
206 mxg
->buffer_ptr
+= size
;
208 if (marker
== APP13
&& size
>= 16) { /* audio data */
209 /* time (GMT) of first sample in usec since 1970, little-endian */
210 pkt
->pts
= pkt
->dts
= AV_RL64(startmarker_ptr
+ 8);
211 pkt
->stream_index
= 1;
212 #if FF_API_DESTRUCT_PACKET
213 pkt
->destruct
= NULL
;
216 pkt
->size
= size
- 14;
217 pkt
->data
= startmarker_ptr
+ 16;
219 if (startmarker_ptr
- mxg
->buffer
> mxg
->cache_size
) {
220 if (mxg
->cache_size
> 0) {
221 memcpy(mxg
->buffer
, mxg
->buffer_ptr
, mxg
->cache_size
);
223 mxg
->buffer_ptr
= mxg
->buffer
;
227 } else if (marker
== COM
&& size
>= 18 &&
228 !strncmp(startmarker_ptr
+ 4, "MXF", 3)) {
229 /* time (GMT) of video frame in usec since 1970, little-endian */
230 mxg
->dts
= AV_RL64(startmarker_ptr
+ 12);
234 /* start marker not found */
235 mxg
->buffer_ptr
= search_end
;
236 mxg
->cache_size
= OVERREAD_SIZE
;
243 static int mxg_close(struct AVFormatContext
*s
)
245 MXGContext
*mxg
= s
->priv_data
;
246 av_freep(&mxg
->buffer
);
250 AVInputFormat ff_mxg_demuxer
= {
252 .long_name
= NULL_IF_CONFIG_SMALL("MxPEG clip"),
253 .priv_data_size
= sizeof(MXGContext
),
254 .read_header
= mxg_read_header
,
255 .read_packet
= mxg_read_packet
,
256 .read_close
= mxg_close
,