00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/channel_layout.h"
00023 #include "libavutil/intreadwrite.h"
00024 #include "libavcodec/mjpeg.h"
00025 #include "avformat.h"
00026 #include "internal.h"
00027 #include "avio.h"
00028
00029 #define DEFAULT_PACKET_SIZE 1024
00030 #define OVERREAD_SIZE 3
00031
00032 typedef struct MXGContext {
00033 uint8_t *buffer;
00034 uint8_t *buffer_ptr;
00035 uint8_t *soi_ptr;
00036 unsigned int buffer_size;
00037 int64_t dts;
00038 unsigned int cache_size;
00039 } MXGContext;
00040
00041 static int mxg_read_header(AVFormatContext *s)
00042 {
00043 AVStream *video_st, *audio_st;
00044 MXGContext *mxg = s->priv_data;
00045
00046
00047 video_st = avformat_new_stream(s, NULL);
00048 if (!video_st)
00049 return AVERROR(ENOMEM);
00050 video_st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00051 video_st->codec->codec_id = AV_CODEC_ID_MXPEG;
00052 avpriv_set_pts_info(video_st, 64, 1, 1000000);
00053
00054 audio_st = avformat_new_stream(s, NULL);
00055 if (!audio_st)
00056 return AVERROR(ENOMEM);
00057 audio_st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00058 audio_st->codec->codec_id = AV_CODEC_ID_PCM_ALAW;
00059 audio_st->codec->channels = 1;
00060 audio_st->codec->channel_layout = AV_CH_LAYOUT_MONO;
00061 audio_st->codec->sample_rate = 8000;
00062 audio_st->codec->bits_per_coded_sample = 8;
00063 audio_st->codec->block_align = 1;
00064 avpriv_set_pts_info(audio_st, 64, 1, 1000000);
00065
00066 mxg->soi_ptr = mxg->buffer_ptr = mxg->buffer = 0;
00067 mxg->buffer_size = 0;
00068 mxg->dts = AV_NOPTS_VALUE;
00069 mxg->cache_size = 0;
00070
00071 return 0;
00072 }
00073
00074 static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end)
00075 {
00076 for (; p < end - 3; p += 4) {
00077 uint32_t x = *(uint32_t*)p;
00078
00079 if (x & (~(x+0x01010101)) & 0x80808080) {
00080 if (p[0] == 0xff) {
00081 return p;
00082 } else if (p[1] == 0xff) {
00083 return p+1;
00084 } else if (p[2] == 0xff) {
00085 return p+2;
00086 } else if (p[3] == 0xff) {
00087 return p+3;
00088 }
00089 }
00090 }
00091
00092 for (; p < end; ++p) {
00093 if (*p == 0xff) return p;
00094 }
00095
00096 return end;
00097 }
00098
00099 static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size)
00100 {
00101 MXGContext *mxg = s->priv_data;
00102 unsigned int current_pos = mxg->buffer_ptr - mxg->buffer;
00103 unsigned int soi_pos;
00104 int ret;
00105
00106
00107 if (current_pos > current_pos + cache_size)
00108 return AVERROR(ENOMEM);
00109 soi_pos = mxg->soi_ptr - mxg->buffer;
00110 mxg->buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size,
00111 current_pos + cache_size +
00112 FF_INPUT_BUFFER_PADDING_SIZE);
00113 if (!mxg->buffer)
00114 return AVERROR(ENOMEM);
00115 mxg->buffer_ptr = mxg->buffer + current_pos;
00116 if (mxg->soi_ptr) mxg->soi_ptr = mxg->buffer + soi_pos;
00117
00118
00119 ret = avio_read(s->pb, mxg->buffer_ptr + mxg->cache_size,
00120 cache_size - mxg->cache_size);
00121 if (ret < 0)
00122 return ret;
00123
00124 mxg->cache_size += ret;
00125
00126 return ret;
00127 }
00128
00129 static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
00130 {
00131 int ret;
00132 unsigned int size;
00133 uint8_t *startmarker_ptr, *end, *search_end, marker;
00134 MXGContext *mxg = s->priv_data;
00135
00136 while (!url_feof(s->pb) && !s->pb->error){
00137 if (mxg->cache_size <= OVERREAD_SIZE) {
00138
00139 ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE);
00140 if (ret < 0)
00141 return ret;
00142 }
00143 end = mxg->buffer_ptr + mxg->cache_size;
00144
00145
00146 if (mxg->cache_size > OVERREAD_SIZE) {
00147 search_end = end - OVERREAD_SIZE;
00148 startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
00149 } else {
00150 search_end = end;
00151 startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
00152 if (startmarker_ptr >= search_end - 1 ||
00153 *(startmarker_ptr + 1) != EOI) break;
00154 }
00155
00156 if (startmarker_ptr != search_end) {
00157 marker = *(startmarker_ptr + 1);
00158 mxg->buffer_ptr = startmarker_ptr + 2;
00159 mxg->cache_size = end - mxg->buffer_ptr;
00160
00161 if (marker == SOI) {
00162 mxg->soi_ptr = startmarker_ptr;
00163 } else if (marker == EOI) {
00164 if (!mxg->soi_ptr) {
00165 av_log(s, AV_LOG_WARNING, "Found EOI before SOI, skipping\n");
00166 continue;
00167 }
00168
00169 pkt->pts = pkt->dts = mxg->dts;
00170 pkt->stream_index = 0;
00171 pkt->destruct = NULL;
00172 pkt->size = mxg->buffer_ptr - mxg->soi_ptr;
00173 pkt->data = mxg->soi_ptr;
00174
00175 if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) {
00176 if (mxg->cache_size > 0) {
00177 memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
00178 }
00179
00180 mxg->buffer_ptr = mxg->buffer;
00181 }
00182 mxg->soi_ptr = 0;
00183
00184 return pkt->size;
00185 } else if ( (SOF0 <= marker && marker <= SOF15) ||
00186 (SOS <= marker && marker <= COM) ) {
00187
00188
00189 size = AV_RB16(mxg->buffer_ptr);
00190 if (size < 2)
00191 return AVERROR(EINVAL);
00192
00193 if (mxg->cache_size < size) {
00194 ret = mxg_update_cache(s, size);
00195 if (ret < 0)
00196 return ret;
00197 startmarker_ptr = mxg->buffer_ptr - 2;
00198 mxg->cache_size = 0;
00199 } else {
00200 mxg->cache_size -= size;
00201 }
00202
00203 mxg->buffer_ptr += size;
00204
00205 if (marker == APP13 && size >= 16) {
00206
00207 pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8);
00208 pkt->stream_index = 1;
00209 pkt->destruct = NULL;
00210 pkt->size = size - 14;
00211 pkt->data = startmarker_ptr + 16;
00212
00213 if (startmarker_ptr - mxg->buffer > mxg->cache_size) {
00214 if (mxg->cache_size > 0) {
00215 memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
00216 }
00217 mxg->buffer_ptr = mxg->buffer;
00218 }
00219
00220 return pkt->size;
00221 } else if (marker == COM && size >= 18 &&
00222 !strncmp(startmarker_ptr + 4, "MXF", 3)) {
00223
00224 mxg->dts = AV_RL64(startmarker_ptr + 12);
00225 }
00226 }
00227 } else {
00228
00229 mxg->buffer_ptr = search_end;
00230 mxg->cache_size = OVERREAD_SIZE;
00231 }
00232 }
00233
00234 return AVERROR_EOF;
00235 }
00236
00237 static int mxg_close(struct AVFormatContext *s)
00238 {
00239 MXGContext *mxg = s->priv_data;
00240 av_freep(&mxg->buffer);
00241 return 0;
00242 }
00243
00244 AVInputFormat ff_mxg_demuxer = {
00245 .name = "mxg",
00246 .long_name = NULL_IF_CONFIG_SMALL("MxPEG clip"),
00247 .priv_data_size = sizeof(MXGContext),
00248 .read_header = mxg_read_header,
00249 .read_packet = mxg_read_packet,
00250 .read_close = mxg_close,
00251 .extensions = "mxg",
00252 };