Mercurial > libavformat.hg
annotate bethsoftvid.c @ 3902:5f9bec099c69 libavformat
Add dynamic payload handlers to rdt.c. These follow the same API as the ones
in rtpdec.c, so that they can be shared and used in the same way in rtsp.c.
The handlers, since they are specific for RDT, are registered in rdt.c and
a new registration function is thus called from allformats.c.
The dynamic payload handler also implements RDT-specific SDP-line parsing for
OpaqueData and StartTime, which are specific for RDT and needed for proper
playback. OpaqueData contains one or a list ("MLTI") of "MDPR" chunks that
can be parsed by the rmdec.c function ff_rm_read_mdpr_codecdata(). To use
this function, we create a new rdt_demuxer, which has the same private data
as the rm_demuxer. The resulting AVFormatContext created with _open_stream()
can thus be used to call functions in the RM demuxer.
See discussion in "Realmedia patch" thread on ML.
author | rbultje |
---|---|
date | Sun, 07 Sep 2008 01:21:24 +0000 |
parents | 7a0230981402 |
children | 1d3d17de20ba |
rev | line source |
---|---|
1989 | 1 /* |
2 * Bethsoft VID format Demuxer | |
3 * Copyright (c) 2007 Nicholas Tung | |
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 bethsoftvid.c | |
24 * @brief Bethesda Softworks VID (.vid) file demuxer | |
25 * @author Nicholas Tung [ntung (at. ntung com] (2007-03) | |
26 * @sa http://wiki.multimedia.cx/index.php?title=Bethsoft_VID | |
27 * @sa http://www.svatopluk.com/andux/docs/dfvid.html | |
28 */ | |
29 | |
30 #include "avformat.h" | |
3286 | 31 #include "libavcodec/bethsoftvideo.h" |
1989 | 32 |
33 typedef struct BVID_DemuxContext | |
34 { | |
35 int nframes; | |
36 /** delay value between frames, added to individual frame delay. | |
37 * custom units, which will be added to other custom units (~=16ms according | |
38 * to free, unofficial documentation) */ | |
39 int bethsoft_global_delay; | |
40 | |
41 /** video presentation time stamp. | |
42 * delay = 16 milliseconds * (global_delay + per_frame_delay) */ | |
1995
df6bcc29a90c
code claims to use 32bit timestamp, lets make it also use that
michael
parents:
1994
diff
changeset
|
43 int video_pts; |
1989 | 44 |
45 int is_finished; | |
46 | |
47 } BVID_DemuxContext; | |
48 | |
49 static int vid_probe(AVProbeData *p) | |
50 { | |
51 // little endian VID tag, file starts with "VID\0" | |
2001
1a3c9056982a
allocate 32 extra bytes at the end of the probe buffer and remove most probe buf_size checks
michael
parents:
1999
diff
changeset
|
52 if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0)) |
1989 | 53 return 0; |
54 | |
55 return AVPROBE_SCORE_MAX; | |
56 } | |
57 | |
58 static int vid_read_header(AVFormatContext *s, | |
59 AVFormatParameters *ap) | |
60 { | |
1994 | 61 BVID_DemuxContext *vid = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
62 ByteIOContext *pb = s->pb; |
1989 | 63 AVStream *stream; |
64 | |
65 /* load main header. Contents: | |
66 * bytes: 'V' 'I' 'D' | |
67 * int16s: always_512, nframes, width, height, delay, always_14 | |
68 */ | |
69 url_fseek(pb, 5, SEEK_CUR); | |
70 vid->nframes = get_le16(pb); | |
71 | |
72 stream = av_new_stream(s, 0); | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
73 if (!stream) |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2232
diff
changeset
|
74 return AVERROR(ENOMEM); |
1989 | 75 av_set_pts_info(stream, 32, 1, 60); // 16 ms increments, i.e. 60 fps |
76 stream->codec->codec_type = CODEC_TYPE_VIDEO; | |
77 stream->codec->codec_id = CODEC_ID_BETHSOFTVID; | |
78 stream->codec->width = get_le16(pb); | |
79 stream->codec->height = get_le16(pb); | |
80 stream->codec->pix_fmt = PIX_FMT_PAL8; | |
81 vid->bethsoft_global_delay = get_le16(pb); | |
82 get_le16(pb); | |
83 | |
84 // done with video codec, set up audio codec | |
85 stream = av_new_stream(s, 0); | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
86 if (!stream) |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2232
diff
changeset
|
87 return AVERROR(ENOMEM); |
1989 | 88 stream->codec->codec_type = CODEC_TYPE_AUDIO; |
89 stream->codec->codec_id = CODEC_ID_PCM_U8; | |
90 stream->codec->channels = 1; | |
91 stream->codec->sample_rate = 11025; | |
92 stream->codec->bits_per_sample = 8; | |
93 stream->codec->bit_rate = stream->codec->channels * stream->codec->sample_rate * stream->codec->bits_per_sample; | |
94 | |
95 return 0; | |
96 } | |
97 | |
98 #define BUFFER_PADDING_SIZE 1000 | |
99 static int read_frame(BVID_DemuxContext *vid, ByteIOContext *pb, AVPacket *pkt, | |
100 uint8_t block_type, AVFormatContext *s, int npixels) | |
101 { | |
102 uint8_t * vidbuf_start = NULL; | |
103 int vidbuf_nbytes = 0; | |
1999 | 104 int code; |
1989 | 105 int bytes_copied = 0; |
106 int position; | |
2232
77ed2f4105b7
bethsoftvid: use correct type for size passed to av_fast_realloc()
mru
parents:
2001
diff
changeset
|
107 unsigned int vidbuf_capacity; |
1989 | 108 |
109 vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE); | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
110 if(!vidbuf_start) |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2232
diff
changeset
|
111 return AVERROR(ENOMEM); |
1989 | 112 |
113 // save the file position for the packet, include block type | |
114 position = url_ftell(pb) - 1; | |
115 | |
116 vidbuf_start[vidbuf_nbytes++] = block_type; | |
117 | |
118 // get the video delay (next int16), and set the presentation time | |
119 vid->video_pts += vid->bethsoft_global_delay + get_le16(pb); | |
120 | |
121 // set the y offset if it exists (decoder header data should be in data section) | |
1996 | 122 if(block_type == VIDEO_YOFF_P_FRAME){ |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
123 if(get_buffer(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) |
1992
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
124 goto fail; |
1989 | 125 vidbuf_nbytes += 2; |
126 } | |
127 | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
128 do{ |
1989 | 129 vidbuf_start = av_fast_realloc(vidbuf_start, &vidbuf_capacity, vidbuf_nbytes + BUFFER_PADDING_SIZE); |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
130 if(!vidbuf_start) |
2273
7eb456c4ed8a
Replace all occurrences of AVERROR_NOMEM with AVERROR(ENOMEM).
takis
parents:
2232
diff
changeset
|
131 return AVERROR(ENOMEM); |
1989 | 132 |
1999 | 133 code = get_byte(pb); |
134 vidbuf_start[vidbuf_nbytes++] = code; | |
1989 | 135 |
1999 | 136 if(code >= 0x80){ // rle sequence |
1996 | 137 if(block_type == VIDEO_I_FRAME) |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
138 vidbuf_start[vidbuf_nbytes++] = get_byte(pb); |
1999 | 139 } else if(code){ // plain sequence |
140 if(get_buffer(pb, &vidbuf_start[vidbuf_nbytes], code) != code) | |
1992
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
141 goto fail; |
1999 | 142 vidbuf_nbytes += code; |
1989 | 143 } |
1999 | 144 bytes_copied += code & 0x7F; |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
145 if(bytes_copied == npixels){ // sometimes no stop character is given, need to keep track of bytes copied |
1989 | 146 // may contain a 0 byte even if read all pixels |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
147 if(get_byte(pb)) |
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
148 url_fseek(pb, -1, SEEK_CUR); |
1989 | 149 break; |
150 } | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
151 if(bytes_copied > npixels) |
1992
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
152 goto fail; |
1999 | 153 } while(code); |
1989 | 154 |
155 // copy data into packet | |
1992
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
156 if(av_new_packet(pkt, vidbuf_nbytes) < 0) |
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
157 goto fail; |
1989 | 158 memcpy(pkt->data, vidbuf_start, vidbuf_nbytes); |
159 av_free(vidbuf_start); | |
160 | |
161 pkt->pos = position; | |
162 pkt->stream_index = 0; // use the video decoder, which was initialized as the first stream | |
163 pkt->pts = vid->video_pts; | |
164 | |
165 vid->nframes--; // used to check if all the frames were read | |
166 return vidbuf_nbytes; | |
1992
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
167 fail: |
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
168 av_free(vidbuf_start); |
c321bada49c7
memleak (seems ive missed that under the obfuscated indention)
michael
parents:
1991
diff
changeset
|
169 return -1; |
1989 | 170 } |
171 | |
172 static int vid_read_packet(AVFormatContext *s, | |
173 AVPacket *pkt) | |
174 { | |
1994 | 175 BVID_DemuxContext *vid = s->priv_data; |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2274
diff
changeset
|
176 ByteIOContext *pb = s->pb; |
1994 | 177 unsigned char block_type; |
1989 | 178 int audio_length; |
179 int ret_value; | |
180 | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
181 if(vid->is_finished || url_feof(pb)) |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
182 return AVERROR(EIO); |
1989 | 183 |
184 block_type = get_byte(pb); | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
185 switch(block_type){ |
1989 | 186 case PALETTE_BLOCK: |
187 url_fseek(pb, -1, SEEK_CUR); // include block type | |
1996 | 188 ret_value = av_get_packet(pb, pkt, 3 * 256 + 1); |
189 if(ret_value != 3 * 256 + 1){ | |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
190 av_free_packet(pkt); |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
191 return AVERROR(EIO); |
1991
999e085b50eb
sane indention (no more 3 statements on one line...)
michael
parents:
1989
diff
changeset
|
192 } |
1989 | 193 pkt->stream_index = 0; |
194 return ret_value; | |
195 | |
196 case FIRST_AUDIO_BLOCK: | |
1994 | 197 get_le16(pb); |
1989 | 198 // soundblaster DAC used for sample rate, as on specification page (link above) |
199 s->streams[1]->codec->sample_rate = 1000000 / (256 - get_byte(pb)); | |
200 s->streams[1]->codec->bit_rate = s->streams[1]->codec->channels * s->streams[1]->codec->sample_rate * s->streams[1]->codec->bits_per_sample; | |
201 case AUDIO_BLOCK: | |
202 audio_length = get_le16(pb); | |
203 ret_value = av_get_packet(pb, pkt, audio_length); | |
204 pkt->stream_index = 1; | |
3278 | 205 return ret_value != audio_length ? AVERROR(EIO) : ret_value; |
1989 | 206 |
1996 | 207 case VIDEO_P_FRAME: |
208 case VIDEO_YOFF_P_FRAME: | |
209 case VIDEO_I_FRAME: | |
1989 | 210 return read_frame(vid, pb, pkt, block_type, s, |
211 s->streams[0]->codec->width * s->streams[0]->codec->height); | |
212 | |
1996 | 213 case EOF_BLOCK: |
1989 | 214 if(vid->nframes != 0) |
215 av_log(s, AV_LOG_VERBOSE, "reached terminating character but not all frames read.\n"); | |
216 vid->is_finished = 1; | |
2274
b21c2af60bc9
Replace all occurrences of AVERROR_IO with AVERROR(EIO).
takis
parents:
2273
diff
changeset
|
217 return AVERROR(EIO); |
1989 | 218 default: |
219 av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n", | |
220 block_type, block_type, block_type); return -1; | |
221 } | |
222 | |
223 return 0; | |
224 } | |
225 | |
226 AVInputFormat bethsoftvid_demuxer = { | |
227 "bethsoftvid", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3286
diff
changeset
|
228 NULL_IF_CONFIG_SMALL("Bethesda Softworks VID format"), |
1989 | 229 sizeof(BVID_DemuxContext), |
230 vid_probe, | |
231 vid_read_header, | |
232 vid_read_packet, | |
233 }; |