annotate ffmpeg/libavformat/yop.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 * Psygnosis YOP demuxer
yading@11 3 *
yading@11 4 * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com>
yading@11 5 * derived from the code by
yading@11 6 * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
yading@11 7 *
yading@11 8 * This file is part of FFmpeg.
yading@11 9 *
yading@11 10 * FFmpeg is free software; you can redistribute it and/or
yading@11 11 * modify it under the terms of the GNU Lesser General Public
yading@11 12 * License as published by the Free Software Foundation; either
yading@11 13 * version 2.1 of the License, or (at your option) any later version.
yading@11 14 *
yading@11 15 * FFmpeg is distributed in the hope that it will be useful,
yading@11 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 18 * Lesser General Public License for more details.
yading@11 19 *
yading@11 20 * You should have received a copy of the GNU Lesser General Public
yading@11 21 * License along with FFmpeg; if not, write to the Free Software
yading@11 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 23 */
yading@11 24
yading@11 25 #include "libavutil/channel_layout.h"
yading@11 26 #include "libavutil/intreadwrite.h"
yading@11 27 #include "avformat.h"
yading@11 28 #include "internal.h"
yading@11 29
yading@11 30 typedef struct yop_dec_context {
yading@11 31 AVPacket video_packet;
yading@11 32
yading@11 33 int odd_frame;
yading@11 34 int frame_size;
yading@11 35 int audio_block_length;
yading@11 36 int palette_size;
yading@11 37 } YopDecContext;
yading@11 38
yading@11 39 static int yop_probe(AVProbeData *probe_packet)
yading@11 40 {
yading@11 41 if (AV_RB16(probe_packet->buf) == AV_RB16("YO") &&
yading@11 42 probe_packet->buf[2]<10 &&
yading@11 43 probe_packet->buf[3]<10 &&
yading@11 44 probe_packet->buf[6] &&
yading@11 45 probe_packet->buf[7] &&
yading@11 46 !(probe_packet->buf[8] & 1) &&
yading@11 47 !(probe_packet->buf[10] & 1) &&
yading@11 48 AV_RL16(probe_packet->buf + 12 + 6) >= 920 &&
yading@11 49 AV_RL16(probe_packet->buf + 12 + 6) < probe_packet->buf[12] * 3 + 4 + probe_packet->buf[7] * 2048
yading@11 50 )
yading@11 51 return AVPROBE_SCORE_MAX * 3 / 4;
yading@11 52
yading@11 53 return 0;
yading@11 54 }
yading@11 55
yading@11 56 static int yop_read_header(AVFormatContext *s)
yading@11 57 {
yading@11 58 YopDecContext *yop = s->priv_data;
yading@11 59 AVIOContext *pb = s->pb;
yading@11 60
yading@11 61 AVCodecContext *audio_dec, *video_dec;
yading@11 62 AVStream *audio_stream, *video_stream;
yading@11 63
yading@11 64 int frame_rate, ret;
yading@11 65
yading@11 66 audio_stream = avformat_new_stream(s, NULL);
yading@11 67 video_stream = avformat_new_stream(s, NULL);
yading@11 68 if (!audio_stream || !video_stream)
yading@11 69 return AVERROR(ENOMEM);
yading@11 70
yading@11 71 // Extra data that will be passed to the decoder
yading@11 72 video_stream->codec->extradata_size = 8;
yading@11 73
yading@11 74 video_stream->codec->extradata = av_mallocz(video_stream->codec->extradata_size +
yading@11 75 FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 76
yading@11 77 if (!video_stream->codec->extradata)
yading@11 78 return AVERROR(ENOMEM);
yading@11 79
yading@11 80 // Audio
yading@11 81 audio_dec = audio_stream->codec;
yading@11 82 audio_dec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 83 audio_dec->codec_id = AV_CODEC_ID_ADPCM_IMA_APC;
yading@11 84 audio_dec->channels = 1;
yading@11 85 audio_dec->channel_layout = AV_CH_LAYOUT_MONO;
yading@11 86 audio_dec->sample_rate = 22050;
yading@11 87
yading@11 88 // Video
yading@11 89 video_dec = video_stream->codec;
yading@11 90 video_dec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 91 video_dec->codec_id = AV_CODEC_ID_YOP;
yading@11 92
yading@11 93 avio_skip(pb, 6);
yading@11 94
yading@11 95 frame_rate = avio_r8(pb);
yading@11 96 yop->frame_size = avio_r8(pb) * 2048;
yading@11 97 video_dec->width = avio_rl16(pb);
yading@11 98 video_dec->height = avio_rl16(pb);
yading@11 99
yading@11 100 video_stream->sample_aspect_ratio = (AVRational){1, 2};
yading@11 101
yading@11 102 ret = avio_read(pb, video_dec->extradata, 8);
yading@11 103 if (ret < 8)
yading@11 104 return ret < 0 ? ret : AVERROR_EOF;
yading@11 105
yading@11 106 yop->palette_size = video_dec->extradata[0] * 3 + 4;
yading@11 107 yop->audio_block_length = AV_RL16(video_dec->extradata + 6);
yading@11 108
yading@11 109 video_dec->bit_rate = 8 * (yop->frame_size - yop->audio_block_length) * frame_rate;
yading@11 110
yading@11 111 // 1840 samples per frame, 1 nibble per sample; hence 1840/2 = 920
yading@11 112 if (yop->audio_block_length < 920 ||
yading@11 113 yop->audio_block_length + yop->palette_size >= yop->frame_size) {
yading@11 114 av_log(s, AV_LOG_ERROR, "YOP has invalid header\n");
yading@11 115 return AVERROR_INVALIDDATA;
yading@11 116 }
yading@11 117
yading@11 118 avio_seek(pb, 2048, SEEK_SET);
yading@11 119
yading@11 120 avpriv_set_pts_info(video_stream, 32, 1, frame_rate);
yading@11 121
yading@11 122 return 0;
yading@11 123 }
yading@11 124
yading@11 125 static int yop_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 126 {
yading@11 127 YopDecContext *yop = s->priv_data;
yading@11 128 AVIOContext *pb = s->pb;
yading@11 129
yading@11 130 int ret;
yading@11 131 int actual_video_data_size = yop->frame_size -
yading@11 132 yop->audio_block_length - yop->palette_size;
yading@11 133
yading@11 134 yop->video_packet.stream_index = 1;
yading@11 135
yading@11 136 if (yop->video_packet.data) {
yading@11 137 *pkt = yop->video_packet;
yading@11 138 memset(&yop->video_packet, 0, sizeof(yop->video_packet));
yading@11 139 pkt->data[0] = yop->odd_frame;
yading@11 140 pkt->flags |= AV_PKT_FLAG_KEY;
yading@11 141 yop->odd_frame ^= 1;
yading@11 142 return pkt->size;
yading@11 143 }
yading@11 144 ret = av_new_packet(&yop->video_packet,
yading@11 145 yop->frame_size - yop->audio_block_length);
yading@11 146 if (ret < 0)
yading@11 147 return ret;
yading@11 148
yading@11 149 yop->video_packet.pos = avio_tell(pb);
yading@11 150
yading@11 151 ret = avio_read(pb, yop->video_packet.data, yop->palette_size);
yading@11 152 if (ret < 0) {
yading@11 153 goto err_out;
yading@11 154 }else if (ret < yop->palette_size) {
yading@11 155 ret = AVERROR_EOF;
yading@11 156 goto err_out;
yading@11 157 }
yading@11 158
yading@11 159 ret = av_get_packet(pb, pkt, 920);
yading@11 160 if (ret < 0)
yading@11 161 goto err_out;
yading@11 162
yading@11 163 // Set position to the start of the frame
yading@11 164 pkt->pos = yop->video_packet.pos;
yading@11 165
yading@11 166 avio_skip(pb, yop->audio_block_length - ret);
yading@11 167
yading@11 168 ret = avio_read(pb, yop->video_packet.data + yop->palette_size,
yading@11 169 actual_video_data_size);
yading@11 170 if (ret < 0)
yading@11 171 goto err_out;
yading@11 172 else if (ret < actual_video_data_size)
yading@11 173 av_shrink_packet(&yop->video_packet, yop->palette_size + ret);
yading@11 174
yading@11 175 // Arbitrarily return the audio data first
yading@11 176 return yop->audio_block_length;
yading@11 177
yading@11 178 err_out:
yading@11 179 av_free_packet(&yop->video_packet);
yading@11 180 return ret;
yading@11 181 }
yading@11 182
yading@11 183 static int yop_read_close(AVFormatContext *s)
yading@11 184 {
yading@11 185 YopDecContext *yop = s->priv_data;
yading@11 186 av_free_packet(&yop->video_packet);
yading@11 187 return 0;
yading@11 188 }
yading@11 189
yading@11 190 static int yop_read_seek(AVFormatContext *s, int stream_index,
yading@11 191 int64_t timestamp, int flags)
yading@11 192 {
yading@11 193 YopDecContext *yop = s->priv_data;
yading@11 194 int64_t frame_pos, pos_min, pos_max;
yading@11 195 int frame_count;
yading@11 196
yading@11 197 if (!stream_index)
yading@11 198 return -1;
yading@11 199
yading@11 200 pos_min = s->data_offset;
yading@11 201 pos_max = avio_size(s->pb) - yop->frame_size;
yading@11 202 frame_count = (pos_max - pos_min) / yop->frame_size;
yading@11 203
yading@11 204 timestamp = FFMAX(0, FFMIN(frame_count, timestamp));
yading@11 205
yading@11 206 frame_pos = timestamp * yop->frame_size + pos_min;
yading@11 207
yading@11 208 if (avio_seek(s->pb, frame_pos, SEEK_SET) < 0)
yading@11 209 return -1;
yading@11 210
yading@11 211 av_free_packet(&yop->video_packet);
yading@11 212 yop->odd_frame = timestamp & 1;
yading@11 213
yading@11 214 return 0;
yading@11 215 }
yading@11 216
yading@11 217 AVInputFormat ff_yop_demuxer = {
yading@11 218 .name = "yop",
yading@11 219 .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP"),
yading@11 220 .priv_data_size = sizeof(YopDecContext),
yading@11 221 .read_probe = yop_probe,
yading@11 222 .read_header = yop_read_header,
yading@11 223 .read_packet = yop_read_packet,
yading@11 224 .read_close = yop_read_close,
yading@11 225 .read_seek = yop_read_seek,
yading@11 226 .extensions = "yop",
yading@11 227 .flags = AVFMT_GENERIC_INDEX,
yading@11 228 };