ffmpeg / libavformat / jvdec.c @ 435535e4
History | View | Annotate | Download (6.77 KB)
1 | 48e0d222 | Peter Ross | /*
|
---|---|---|---|
2 | * Bitmap Brothers JV demuxer
|
||
3 | * Copyright (c) 2005, 2011 Peter Ross <pross@xvid.org>
|
||
4 | *
|
||
5 | * This file is part of FFmpeg.
|
||
6 | *
|
||
7 | * FFmpeg is free software; you can redistribute it and/or
|
||
8 | * modify it under the terms of the GNU Lesser General Public
|
||
9 | * License as published by the Free Software Foundation; either
|
||
10 | * version 2.1 of the License, or (at your option) any later version.
|
||
11 | *
|
||
12 | * FFmpeg is distributed in the hope that it will be useful,
|
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
15 | * Lesser General Public License for more details.
|
||
16 | *
|
||
17 | * You should have received a copy of the GNU Lesser General Public
|
||
18 | * License along with FFmpeg; if not, write to the Free Software
|
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
20 | */
|
||
21 | |||
22 | /**
|
||
23 | * @file
|
||
24 | * Bitmap Brothers JV demuxer
|
||
25 | * @author Peter Ross <pross@xvid.org>
|
||
26 | */
|
||
27 | |||
28 | #include "libavutil/intreadwrite.h" |
||
29 | #include "avformat.h" |
||
30 | |||
31 | 57d63d43 | Peter Ross | #define JV_PREAMBLE_SIZE 5 |
32 | |||
33 | 48e0d222 | Peter Ross | typedef struct { |
34 | int audio_size; /** audio packet size (bytes) */ |
||
35 | int video_size; /** video packet size (bytes) */ |
||
36 | 2f1084ca | Peter Ross | int palette_size; /** palette size (bytes) */ |
37 | 48e0d222 | Peter Ross | int video_type; /** per-frame video compression type */ |
38 | } JVFrame; |
||
39 | |||
40 | typedef struct { |
||
41 | JVFrame *frames; |
||
42 | enum {
|
||
43 | JV_AUDIO = 0,
|
||
44 | JV_VIDEO, |
||
45 | JV_PADDING |
||
46 | } state; |
||
47 | int64_t pts; |
||
48 | } JVDemuxContext; |
||
49 | |||
50 | #define MAGIC " Compression by John M Phillips Copyright (C) 1995 The Bitmap Brothers Ltd." |
||
51 | |||
52 | static int read_probe(AVProbeData *pd) |
||
53 | { |
||
54 | if (pd->buf[0] == 'J' && pd->buf[1] == 'V' && |
||
55 | !memcmp(pd->buf + 4, MAGIC, FFMIN(strlen(MAGIC), pd->buf_size - 4))) |
||
56 | return AVPROBE_SCORE_MAX;
|
||
57 | return 0; |
||
58 | } |
||
59 | |||
60 | static int read_header(AVFormatContext *s, |
||
61 | AVFormatParameters *ap) |
||
62 | { |
||
63 | JVDemuxContext *jv = s->priv_data; |
||
64 | AVIOContext *pb = s->pb; |
||
65 | AVStream *vst, *ast; |
||
66 | int64_t audio_pts = 0;
|
||
67 | int64_t offset; |
||
68 | int i;
|
||
69 | |||
70 | avio_skip(pb, 80);
|
||
71 | |||
72 | ast = av_new_stream(s, 0);
|
||
73 | vst = av_new_stream(s, 1);
|
||
74 | if (!ast || !vst)
|
||
75 | return AVERROR(ENOMEM);
|
||
76 | |||
77 | vst->codec->codec_type = CODEC_TYPE_VIDEO; |
||
78 | vst->codec->codec_id = CODEC_ID_JV; |
||
79 | vst->codec->codec_tag = 0; /* no fourcc */ |
||
80 | vst->codec->width = avio_rl16(pb); |
||
81 | vst->codec->height = avio_rl16(pb); |
||
82 | vst->nb_frames = |
||
83 | ast->nb_index_entries = avio_rl16(pb); |
||
84 | av_set_pts_info(vst, 64, avio_rl16(pb), 1000); |
||
85 | |||
86 | avio_skip(pb, 4);
|
||
87 | |||
88 | ast->codec->codec_type = CODEC_TYPE_AUDIO; |
||
89 | ast->codec->codec_id = CODEC_ID_PCM_U8; |
||
90 | ast->codec->codec_tag = 0; /* no fourcc */ |
||
91 | ast->codec->sample_rate = avio_rl16(pb); |
||
92 | ast->codec->channels = 1;
|
||
93 | av_set_pts_info(ast, 64, 1, ast->codec->sample_rate); |
||
94 | |||
95 | avio_skip(pb, 10);
|
||
96 | |||
97 | ast->index_entries = av_malloc(ast->nb_index_entries * sizeof(*ast->index_entries));
|
||
98 | if (!ast->index_entries)
|
||
99 | return AVERROR(ENOMEM);
|
||
100 | |||
101 | jv->frames = av_malloc(ast->nb_index_entries * sizeof(JVFrame));
|
||
102 | if (!jv->frames)
|
||
103 | return AVERROR(ENOMEM);
|
||
104 | |||
105 | offset = 0x68 + ast->nb_index_entries * 16; |
||
106 | for(i = 0; i < ast->nb_index_entries; i++) { |
||
107 | AVIndexEntry *e = ast->index_entries + i; |
||
108 | JVFrame *jvf = jv->frames + i; |
||
109 | |||
110 | /* total frame size including audio, video, palette data and padding */
|
||
111 | e->size = avio_rl32(pb); |
||
112 | e->timestamp = i; |
||
113 | e->pos = offset; |
||
114 | offset += e->size; |
||
115 | |||
116 | jvf->audio_size = avio_rl32(pb); |
||
117 | jvf->video_size = avio_rl32(pb); |
||
118 | 2f1084ca | Peter Ross | jvf->palette_size = avio_r8(pb) ? 768 : 0; |
119 | 435535e4 | Peter Ross | jvf->video_size = FFMIN(FFMAX(jvf->video_size, 0),
|
120 | INT_MAX - JV_PREAMBLE_SIZE - jvf->palette_size); |
||
121 | 48e0d222 | Peter Ross | if (avio_r8(pb))
|
122 | av_log(s, AV_LOG_WARNING, "unsupported audio codec\n");
|
||
123 | jvf->video_type = avio_r8(pb); |
||
124 | avio_skip(pb, 1);
|
||
125 | |||
126 | e->timestamp = jvf->audio_size ? audio_pts : AV_NOPTS_VALUE; |
||
127 | audio_pts += jvf->audio_size; |
||
128 | |||
129 | e->flags = jvf->video_type != 1 ? AVINDEX_KEYFRAME : 0; |
||
130 | } |
||
131 | |||
132 | jv->state = JV_AUDIO; |
||
133 | return 0; |
||
134 | } |
||
135 | |||
136 | static int read_packet(AVFormatContext *s, AVPacket *pkt) |
||
137 | { |
||
138 | JVDemuxContext *jv = s->priv_data; |
||
139 | AVIOContext *pb = s->pb; |
||
140 | AVStream *ast = s->streams[0];
|
||
141 | |||
142 | while (!url_feof(s->pb) && jv->pts < ast->nb_index_entries) {
|
||
143 | const AVIndexEntry *e = ast->index_entries + jv->pts;
|
||
144 | const JVFrame *jvf = jv->frames + jv->pts;
|
||
145 | |||
146 | switch(jv->state) {
|
||
147 | case JV_AUDIO:
|
||
148 | jv->state++; |
||
149 | if (jvf->audio_size ) {
|
||
150 | if (av_get_packet(s->pb, pkt, jvf->audio_size) < 0) |
||
151 | return AVERROR(ENOMEM);
|
||
152 | pkt->stream_index = 0;
|
||
153 | pkt->pts = e->timestamp; |
||
154 | pkt->flags |= PKT_FLAG_KEY; |
||
155 | return 0; |
||
156 | } |
||
157 | case JV_VIDEO:
|
||
158 | jv->state++; |
||
159 | 2f1084ca | Peter Ross | if (jvf->video_size || jvf->palette_size) {
|
160 | int size = jvf->video_size + jvf->palette_size;
|
||
161 | 57d63d43 | Peter Ross | if (av_new_packet(pkt, size + JV_PREAMBLE_SIZE))
|
162 | 48e0d222 | Peter Ross | return AVERROR(ENOMEM);
|
163 | |||
164 | AV_WL32(pkt->data, jvf->video_size); |
||
165 | pkt->data[4] = jvf->video_type;
|
||
166 | 57d63d43 | Peter Ross | if (avio_read(pb, pkt->data + JV_PREAMBLE_SIZE, size) < 0) |
167 | 48e0d222 | Peter Ross | return AVERROR(EIO);
|
168 | |||
169 | 57d63d43 | Peter Ross | pkt->size = size + JV_PREAMBLE_SIZE; |
170 | 48e0d222 | Peter Ross | pkt->stream_index = 1;
|
171 | pkt->pts = jv->pts; |
||
172 | if (jvf->video_type != 1) |
||
173 | pkt->flags |= PKT_FLAG_KEY; |
||
174 | return 0; |
||
175 | } |
||
176 | case JV_PADDING:
|
||
177 | avio_skip(pb, FFMAX(e->size - jvf->audio_size - jvf->video_size |
||
178 | 2f1084ca | Peter Ross | - jvf->palette_size, 0));
|
179 | 48e0d222 | Peter Ross | jv->state = JV_AUDIO; |
180 | jv->pts++; |
||
181 | } |
||
182 | } |
||
183 | |||
184 | return AVERROR(EIO);
|
||
185 | } |
||
186 | |||
187 | static int read_seek(AVFormatContext *s, int stream_index, |
||
188 | int64_t ts, int flags)
|
||
189 | { |
||
190 | JVDemuxContext *jv = s->priv_data; |
||
191 | AVStream *ast = s->streams[0];
|
||
192 | int i;
|
||
193 | |||
194 | if (flags & (AVSEEK_FLAG_BYTE|AVSEEK_FLAG_FRAME))
|
||
195 | return AVERROR_NOTSUPP;
|
||
196 | |||
197 | switch(stream_index) {
|
||
198 | case 0: |
||
199 | i = av_index_search_timestamp(ast, ts, flags); |
||
200 | break;
|
||
201 | case 1: |
||
202 | i = ts; |
||
203 | break;
|
||
204 | default:
|
||
205 | return 0; |
||
206 | } |
||
207 | |||
208 | if (i < 0 || i >= ast->nb_index_entries) |
||
209 | return 0; |
||
210 | |||
211 | jv->state = JV_AUDIO; |
||
212 | jv->pts = i; |
||
213 | avio_seek(s->pb, ast->index_entries[i].pos, SEEK_SET); |
||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | AVInputFormat ff_jv_demuxer = { |
||
218 | .name = "jv",
|
||
219 | .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV"),
|
||
220 | .priv_data_size = sizeof(JVDemuxContext),
|
||
221 | .read_probe = read_probe, |
||
222 | .read_header = read_header, |
||
223 | .read_packet = read_packet, |
||
224 | .read_seek = read_seek, |
||
225 | }; |