Libav 0.7.1
|
00001 /* 00002 * Bitmap Brothers JV demuxer 00003 * Copyright (c) 2005, 2011 Peter Ross <pross@xvid.org> 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00028 #include "libavutil/intreadwrite.h" 00029 #include "avformat.h" 00030 00031 #define JV_PREAMBLE_SIZE 5 00032 00033 typedef struct { 00034 int audio_size; 00035 int video_size; 00036 int palette_size; 00037 int video_type; 00038 } JVFrame; 00039 00040 typedef struct { 00041 JVFrame *frames; 00042 enum { 00043 JV_AUDIO = 0, 00044 JV_VIDEO, 00045 JV_PADDING 00046 } state; 00047 int64_t pts; 00048 } JVDemuxContext; 00049 00050 #define MAGIC " Compression by John M Phillips Copyright (C) 1995 The Bitmap Brothers Ltd." 00051 00052 static int read_probe(AVProbeData *pd) 00053 { 00054 if (pd->buf[0] == 'J' && pd->buf[1] == 'V' && 00055 !memcmp(pd->buf + 4, MAGIC, FFMIN(strlen(MAGIC), pd->buf_size - 4))) 00056 return AVPROBE_SCORE_MAX; 00057 return 0; 00058 } 00059 00060 static int read_header(AVFormatContext *s, 00061 AVFormatParameters *ap) 00062 { 00063 JVDemuxContext *jv = s->priv_data; 00064 AVIOContext *pb = s->pb; 00065 AVStream *vst, *ast; 00066 int64_t audio_pts = 0; 00067 int64_t offset; 00068 int i; 00069 00070 avio_skip(pb, 80); 00071 00072 ast = av_new_stream(s, 0); 00073 vst = av_new_stream(s, 1); 00074 if (!ast || !vst) 00075 return AVERROR(ENOMEM); 00076 00077 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00078 vst->codec->codec_id = CODEC_ID_JV; 00079 vst->codec->codec_tag = 0; /* no fourcc */ 00080 vst->codec->width = avio_rl16(pb); 00081 vst->codec->height = avio_rl16(pb); 00082 vst->nb_frames = 00083 ast->nb_index_entries = avio_rl16(pb); 00084 av_set_pts_info(vst, 64, avio_rl16(pb), 1000); 00085 00086 avio_skip(pb, 4); 00087 00088 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00089 ast->codec->codec_id = CODEC_ID_PCM_U8; 00090 ast->codec->codec_tag = 0; /* no fourcc */ 00091 ast->codec->sample_rate = avio_rl16(pb); 00092 ast->codec->channels = 1; 00093 av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); 00094 00095 avio_skip(pb, 10); 00096 00097 ast->index_entries = av_malloc(ast->nb_index_entries * sizeof(*ast->index_entries)); 00098 if (!ast->index_entries) 00099 return AVERROR(ENOMEM); 00100 00101 jv->frames = av_malloc(ast->nb_index_entries * sizeof(JVFrame)); 00102 if (!jv->frames) 00103 return AVERROR(ENOMEM); 00104 00105 offset = 0x68 + ast->nb_index_entries * 16; 00106 for(i = 0; i < ast->nb_index_entries; i++) { 00107 AVIndexEntry *e = ast->index_entries + i; 00108 JVFrame *jvf = jv->frames + i; 00109 00110 /* total frame size including audio, video, palette data and padding */ 00111 e->size = avio_rl32(pb); 00112 e->timestamp = i; 00113 e->pos = offset; 00114 offset += e->size; 00115 00116 jvf->audio_size = avio_rl32(pb); 00117 jvf->video_size = avio_rl32(pb); 00118 jvf->palette_size = avio_r8(pb) ? 768 : 0; 00119 jvf->video_size = FFMIN(FFMAX(jvf->video_size, 0), 00120 INT_MAX - JV_PREAMBLE_SIZE - jvf->palette_size); 00121 if (avio_r8(pb)) 00122 av_log(s, AV_LOG_WARNING, "unsupported audio codec\n"); 00123 jvf->video_type = avio_r8(pb); 00124 avio_skip(pb, 1); 00125 00126 e->timestamp = jvf->audio_size ? audio_pts : AV_NOPTS_VALUE; 00127 audio_pts += jvf->audio_size; 00128 00129 e->flags = jvf->video_type != 1 ? AVINDEX_KEYFRAME : 0; 00130 } 00131 00132 jv->state = JV_AUDIO; 00133 return 0; 00134 } 00135 00136 static int read_packet(AVFormatContext *s, AVPacket *pkt) 00137 { 00138 JVDemuxContext *jv = s->priv_data; 00139 AVIOContext *pb = s->pb; 00140 AVStream *ast = s->streams[0]; 00141 00142 while (!s->pb->eof_reached && jv->pts < ast->nb_index_entries) { 00143 const AVIndexEntry *e = ast->index_entries + jv->pts; 00144 const JVFrame *jvf = jv->frames + jv->pts; 00145 00146 switch(jv->state) { 00147 case JV_AUDIO: 00148 jv->state++; 00149 if (jvf->audio_size ) { 00150 if (av_get_packet(s->pb, pkt, jvf->audio_size) < 0) 00151 return AVERROR(ENOMEM); 00152 pkt->stream_index = 0; 00153 pkt->pts = e->timestamp; 00154 pkt->flags |= AV_PKT_FLAG_KEY; 00155 return 0; 00156 } 00157 case JV_VIDEO: 00158 jv->state++; 00159 if (jvf->video_size || jvf->palette_size) { 00160 int size = jvf->video_size + jvf->palette_size; 00161 if (av_new_packet(pkt, size + JV_PREAMBLE_SIZE)) 00162 return AVERROR(ENOMEM); 00163 00164 AV_WL32(pkt->data, jvf->video_size); 00165 pkt->data[4] = jvf->video_type; 00166 if (avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size) < 0) 00167 return AVERROR(EIO); 00168 00169 pkt->size = size + JV_PREAMBLE_SIZE; 00170 pkt->stream_index = 1; 00171 pkt->pts = jv->pts; 00172 if (jvf->video_type != 1) 00173 pkt->flags |= AV_PKT_FLAG_KEY; 00174 return 0; 00175 } 00176 case JV_PADDING: 00177 avio_skip(pb, FFMAX(e->size - jvf->audio_size - jvf->video_size 00178 - jvf->palette_size, 0)); 00179 jv->state = JV_AUDIO; 00180 jv->pts++; 00181 } 00182 } 00183 00184 return AVERROR(EIO); 00185 } 00186 00187 static int read_seek(AVFormatContext *s, int stream_index, 00188 int64_t ts, int flags) 00189 { 00190 JVDemuxContext *jv = s->priv_data; 00191 AVStream *ast = s->streams[0]; 00192 int i; 00193 00194 if (flags & (AVSEEK_FLAG_BYTE|AVSEEK_FLAG_FRAME)) 00195 return AVERROR(ENOSYS); 00196 00197 switch(stream_index) { 00198 case 0: 00199 i = av_index_search_timestamp(ast, ts, flags); 00200 break; 00201 case 1: 00202 i = ts; 00203 break; 00204 default: 00205 return 0; 00206 } 00207 00208 if (i < 0 || i >= ast->nb_index_entries) 00209 return 0; 00210 00211 jv->state = JV_AUDIO; 00212 jv->pts = i; 00213 avio_seek(s->pb, ast->index_entries[i].pos, SEEK_SET); 00214 return 0; 00215 } 00216 00217 AVInputFormat ff_jv_demuxer = { 00218 .name = "jv", 00219 .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"), 00220 .priv_data_size = sizeof(JVDemuxContext), 00221 .read_probe = read_probe, 00222 .read_header = read_header, 00223 .read_packet = read_packet, 00224 .read_seek = read_seek, 00225 };