annotate ffmpeg/libavformat/mxg.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * MxPEG clip file demuxer
yading@11 3 * Copyright (c) 2010 Anatoly Nenashev
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 #include "libavutil/channel_layout.h"
yading@11 23 #include "libavutil/intreadwrite.h"
yading@11 24 #include "libavcodec/mjpeg.h"
yading@11 25 #include "avformat.h"
yading@11 26 #include "internal.h"
yading@11 27 #include "avio.h"
yading@11 28
yading@11 29 #define DEFAULT_PACKET_SIZE 1024
yading@11 30 #define OVERREAD_SIZE 3
yading@11 31
yading@11 32 typedef struct MXGContext {
yading@11 33 uint8_t *buffer;
yading@11 34 uint8_t *buffer_ptr;
yading@11 35 uint8_t *soi_ptr;
yading@11 36 unsigned int buffer_size;
yading@11 37 int64_t dts;
yading@11 38 unsigned int cache_size;
yading@11 39 } MXGContext;
yading@11 40
yading@11 41 static int mxg_read_header(AVFormatContext *s)
yading@11 42 {
yading@11 43 AVStream *video_st, *audio_st;
yading@11 44 MXGContext *mxg = s->priv_data;
yading@11 45
yading@11 46 /* video parameters will be extracted from the compressed bitstream */
yading@11 47 video_st = avformat_new_stream(s, NULL);
yading@11 48 if (!video_st)
yading@11 49 return AVERROR(ENOMEM);
yading@11 50 video_st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 51 video_st->codec->codec_id = AV_CODEC_ID_MXPEG;
yading@11 52 avpriv_set_pts_info(video_st, 64, 1, 1000000);
yading@11 53
yading@11 54 audio_st = avformat_new_stream(s, NULL);
yading@11 55 if (!audio_st)
yading@11 56 return AVERROR(ENOMEM);
yading@11 57 audio_st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 58 audio_st->codec->codec_id = AV_CODEC_ID_PCM_ALAW;
yading@11 59 audio_st->codec->channels = 1;
yading@11 60 audio_st->codec->channel_layout = AV_CH_LAYOUT_MONO;
yading@11 61 audio_st->codec->sample_rate = 8000;
yading@11 62 audio_st->codec->bits_per_coded_sample = 8;
yading@11 63 audio_st->codec->block_align = 1;
yading@11 64 avpriv_set_pts_info(audio_st, 64, 1, 1000000);
yading@11 65
yading@11 66 mxg->soi_ptr = mxg->buffer_ptr = mxg->buffer = 0;
yading@11 67 mxg->buffer_size = 0;
yading@11 68 mxg->dts = AV_NOPTS_VALUE;
yading@11 69 mxg->cache_size = 0;
yading@11 70
yading@11 71 return 0;
yading@11 72 }
yading@11 73
yading@11 74 static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end)
yading@11 75 {
yading@11 76 for (; p < end - 3; p += 4) {
yading@11 77 uint32_t x = *(uint32_t*)p;
yading@11 78
yading@11 79 if (x & (~(x+0x01010101)) & 0x80808080) {
yading@11 80 if (p[0] == 0xff) {
yading@11 81 return p;
yading@11 82 } else if (p[1] == 0xff) {
yading@11 83 return p+1;
yading@11 84 } else if (p[2] == 0xff) {
yading@11 85 return p+2;
yading@11 86 } else if (p[3] == 0xff) {
yading@11 87 return p+3;
yading@11 88 }
yading@11 89 }
yading@11 90 }
yading@11 91
yading@11 92 for (; p < end; ++p) {
yading@11 93 if (*p == 0xff) return p;
yading@11 94 }
yading@11 95
yading@11 96 return end;
yading@11 97 }
yading@11 98
yading@11 99 static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size)
yading@11 100 {
yading@11 101 MXGContext *mxg = s->priv_data;
yading@11 102 unsigned int current_pos = mxg->buffer_ptr - mxg->buffer;
yading@11 103 unsigned int soi_pos;
yading@11 104 uint8_t *buffer;
yading@11 105 int ret;
yading@11 106
yading@11 107 /* reallocate internal buffer */
yading@11 108 if (current_pos > current_pos + cache_size)
yading@11 109 return AVERROR(ENOMEM);
yading@11 110 soi_pos = mxg->soi_ptr - mxg->buffer;
yading@11 111 buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size,
yading@11 112 current_pos + cache_size +
yading@11 113 FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 114 if (!buffer)
yading@11 115 return AVERROR(ENOMEM);
yading@11 116 mxg->buffer = buffer;
yading@11 117 mxg->buffer_ptr = mxg->buffer + current_pos;
yading@11 118 if (mxg->soi_ptr) mxg->soi_ptr = mxg->buffer + soi_pos;
yading@11 119
yading@11 120 /* get data */
yading@11 121 ret = avio_read(s->pb, mxg->buffer_ptr + mxg->cache_size,
yading@11 122 cache_size - mxg->cache_size);
yading@11 123 if (ret < 0)
yading@11 124 return ret;
yading@11 125
yading@11 126 mxg->cache_size += ret;
yading@11 127
yading@11 128 return ret;
yading@11 129 }
yading@11 130
yading@11 131 static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 132 {
yading@11 133 int ret;
yading@11 134 unsigned int size;
yading@11 135 uint8_t *startmarker_ptr, *end, *search_end, marker;
yading@11 136 MXGContext *mxg = s->priv_data;
yading@11 137
yading@11 138 while (!url_feof(s->pb) && !s->pb->error){
yading@11 139 if (mxg->cache_size <= OVERREAD_SIZE) {
yading@11 140 /* update internal buffer */
yading@11 141 ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE);
yading@11 142 if (ret < 0)
yading@11 143 return ret;
yading@11 144 }
yading@11 145 end = mxg->buffer_ptr + mxg->cache_size;
yading@11 146
yading@11 147 /* find start marker - 0xff */
yading@11 148 if (mxg->cache_size > OVERREAD_SIZE) {
yading@11 149 search_end = end - OVERREAD_SIZE;
yading@11 150 startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
yading@11 151 } else {
yading@11 152 search_end = end;
yading@11 153 startmarker_ptr = mxg_find_startmarker(mxg->buffer_ptr, search_end);
yading@11 154 if (startmarker_ptr >= search_end - 1 ||
yading@11 155 *(startmarker_ptr + 1) != EOI) break;
yading@11 156 }
yading@11 157
yading@11 158 if (startmarker_ptr != search_end) { /* start marker found */
yading@11 159 marker = *(startmarker_ptr + 1);
yading@11 160 mxg->buffer_ptr = startmarker_ptr + 2;
yading@11 161 mxg->cache_size = end - mxg->buffer_ptr;
yading@11 162
yading@11 163 if (marker == SOI) {
yading@11 164 mxg->soi_ptr = startmarker_ptr;
yading@11 165 } else if (marker == EOI) {
yading@11 166 if (!mxg->soi_ptr) {
yading@11 167 av_log(s, AV_LOG_WARNING, "Found EOI before SOI, skipping\n");
yading@11 168 continue;
yading@11 169 }
yading@11 170
yading@11 171 pkt->pts = pkt->dts = mxg->dts;
yading@11 172 pkt->stream_index = 0;
yading@11 173 #if FF_API_DESTRUCT_PACKET
yading@11 174 pkt->destruct = NULL;
yading@11 175 #endif
yading@11 176 pkt->buf = NULL;
yading@11 177 pkt->size = mxg->buffer_ptr - mxg->soi_ptr;
yading@11 178 pkt->data = mxg->soi_ptr;
yading@11 179
yading@11 180 if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) {
yading@11 181 if (mxg->cache_size > 0) {
yading@11 182 memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
yading@11 183 }
yading@11 184
yading@11 185 mxg->buffer_ptr = mxg->buffer;
yading@11 186 }
yading@11 187 mxg->soi_ptr = 0;
yading@11 188
yading@11 189 return pkt->size;
yading@11 190 } else if ( (SOF0 <= marker && marker <= SOF15) ||
yading@11 191 (SOS <= marker && marker <= COM) ) {
yading@11 192 /* all other markers that start marker segment also contain
yading@11 193 length value (see specification for JPEG Annex B.1) */
yading@11 194 size = AV_RB16(mxg->buffer_ptr);
yading@11 195 if (size < 2)
yading@11 196 return AVERROR(EINVAL);
yading@11 197
yading@11 198 if (mxg->cache_size < size) {
yading@11 199 ret = mxg_update_cache(s, size);
yading@11 200 if (ret < 0)
yading@11 201 return ret;
yading@11 202 startmarker_ptr = mxg->buffer_ptr - 2;
yading@11 203 mxg->cache_size = 0;
yading@11 204 } else {
yading@11 205 mxg->cache_size -= size;
yading@11 206 }
yading@11 207
yading@11 208 mxg->buffer_ptr += size;
yading@11 209
yading@11 210 if (marker == APP13 && size >= 16) { /* audio data */
yading@11 211 /* time (GMT) of first sample in usec since 1970, little-endian */
yading@11 212 pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8);
yading@11 213 pkt->stream_index = 1;
yading@11 214 #if FF_API_DESTRUCT_PACKET
yading@11 215 pkt->destruct = NULL;
yading@11 216 #endif
yading@11 217 pkt->buf = NULL;
yading@11 218 pkt->size = size - 14;
yading@11 219 pkt->data = startmarker_ptr + 16;
yading@11 220
yading@11 221 if (startmarker_ptr - mxg->buffer > mxg->cache_size) {
yading@11 222 if (mxg->cache_size > 0) {
yading@11 223 memcpy(mxg->buffer, mxg->buffer_ptr, mxg->cache_size);
yading@11 224 }
yading@11 225 mxg->buffer_ptr = mxg->buffer;
yading@11 226 }
yading@11 227
yading@11 228 return pkt->size;
yading@11 229 } else if (marker == COM && size >= 18 &&
yading@11 230 !strncmp(startmarker_ptr + 4, "MXF", 3)) {
yading@11 231 /* time (GMT) of video frame in usec since 1970, little-endian */
yading@11 232 mxg->dts = AV_RL64(startmarker_ptr + 12);
yading@11 233 }
yading@11 234 }
yading@11 235 } else {
yading@11 236 /* start marker not found */
yading@11 237 mxg->buffer_ptr = search_end;
yading@11 238 mxg->cache_size = OVERREAD_SIZE;
yading@11 239 }
yading@11 240 }
yading@11 241
yading@11 242 return AVERROR_EOF;
yading@11 243 }
yading@11 244
yading@11 245 static int mxg_close(struct AVFormatContext *s)
yading@11 246 {
yading@11 247 MXGContext *mxg = s->priv_data;
yading@11 248 av_freep(&mxg->buffer);
yading@11 249 return 0;
yading@11 250 }
yading@11 251
yading@11 252 AVInputFormat ff_mxg_demuxer = {
yading@11 253 .name = "mxg",
yading@11 254 .long_name = NULL_IF_CONFIG_SMALL("MxPEG clip"),
yading@11 255 .priv_data_size = sizeof(MXGContext),
yading@11 256 .read_header = mxg_read_header,
yading@11 257 .read_packet = mxg_read_packet,
yading@11 258 .read_close = mxg_close,
yading@11 259 .extensions = "mxg",
yading@11 260 };