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