diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-02-17 00:35:06 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-02-17 00:35:06 +0100 |
commit | 8c1ebdcea2d3f84bd5c01ce3dce5e619c845bc0f (patch) | |
tree | 977c2d42de80b6c292ff0f9ad79f14762ba792f6 /libavformat/bethsoftvid.c | |
parent | 7bdefc0f1281c2c18375197985fcd5109e711829 (diff) | |
parent | 204cb29b3c84a74cbcd059d353c70c8bdc567d98 (diff) | |
download | ffmpeg-8c1ebdcea2d3f84bd5c01ce3dce5e619c845bc0f.tar.gz |
Merge remote-tracking branch 'qatar/master'
* qatar/master:
shorten: Use separate pointers for the allocated memory for decoded samples.
atrac3: Fix crash in tonal component decoding.
ws_snd1: Fix wrong samples counts.
movenc: Don't set a default sample duration when creating ismv
rtp: Factorize the check for distinguishing RTCP packets from RTP
golomb: avoid infinite loop on all-zero input (or end of buffer).
bethsoftvid: synchronize video timestamps with audio sample rate
bethsoftvid: add audio stream only after getting the first audio packet
bethsoftvid: Set video packet duration instead of accumulating pts.
bethsoftvid: set packet key frame flag for audio and I-frame video packets.
bethsoftvid: fix read_packet() return codes.
bethsoftvid: pass palette in side data instead of in a separate packet.
sdp: Ignore RTCP packets when autodetecting RTP streams
proresenc: initialise 'sign' variable
mpegaudio: replace memcpy by SIMD code
vc1: prevent using last_frame as a reference for I/P first frame.
Conflicts:
libavcodec/atrac3.c
libavcodec/golomb.h
libavcodec/shorten.c
libavcodec/ws-snd1.c
tests/ref/fate/bethsoft-vid
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat/bethsoftvid.c')
-rw-r--r-- | libavformat/bethsoftvid.c | 162 |
1 files changed, 111 insertions, 51 deletions
diff --git a/libavformat/bethsoftvid.c b/libavformat/bethsoftvid.c index e1786c9351..a98b1bda2c 100644 --- a/libavformat/bethsoftvid.c +++ b/libavformat/bethsoftvid.c @@ -32,17 +32,23 @@ #include "internal.h" #include "libavcodec/bethsoftvideo.h" +#define BVID_PALETTE_SIZE 3 * 256 + +#define DEFAULT_SAMPLE_RATE 11111 + typedef struct BVID_DemuxContext { int nframes; + int sample_rate; /**< audio sample rate */ + int width; /**< video width */ + int height; /**< video height */ /** delay value between frames, added to individual frame delay. * custom units, which will be added to other custom units (~=16ms according * to free, unofficial documentation) */ int bethsoft_global_delay; - - /** video presentation time stamp. - * delay = 16 milliseconds * (global_delay + per_frame_delay) */ - int video_pts; + int video_index; /**< video stream index */ + int audio_index; /**< audio stream index */ + uint8_t *palette; int is_finished; @@ -61,7 +67,6 @@ static int vid_read_header(AVFormatContext *s) { BVID_DemuxContext *vid = s->priv_data; AVIOContext *pb = s->pb; - AVStream *stream; /* load main header. Contents: * bytes: 'V' 'I' 'D' @@ -69,43 +74,50 @@ static int vid_read_header(AVFormatContext *s) */ avio_skip(pb, 5); vid->nframes = avio_rl16(pb); - - stream = avformat_new_stream(s, NULL); - if (!stream) - return AVERROR(ENOMEM); - avpriv_set_pts_info(stream, 32, 1, 60); // 16 ms increments, i.e. 60 fps - stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; - stream->codec->codec_id = CODEC_ID_BETHSOFTVID; - stream->codec->width = avio_rl16(pb); - stream->codec->height = avio_rl16(pb); - stream->codec->pix_fmt = PIX_FMT_PAL8; + vid->width = avio_rl16(pb); + vid->height = avio_rl16(pb); vid->bethsoft_global_delay = avio_rl16(pb); avio_rl16(pb); - // done with video codec, set up audio codec - stream = avformat_new_stream(s, NULL); - if (!stream) - return AVERROR(ENOMEM); - stream->codec->codec_type = AVMEDIA_TYPE_AUDIO; - stream->codec->codec_id = CODEC_ID_PCM_U8; - stream->codec->channels = 1; - stream->codec->sample_rate = 11025; - stream->codec->bits_per_coded_sample = 8; - stream->codec->bit_rate = stream->codec->channels * stream->codec->sample_rate * stream->codec->bits_per_coded_sample; + // wait until the first packet to create each stream + vid->video_index = -1; + vid->audio_index = -1; + vid->sample_rate = DEFAULT_SAMPLE_RATE; + s->ctx_flags |= AVFMTCTX_NOHEADER; return 0; } #define BUFFER_PADDING_SIZE 1000 static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt, - uint8_t block_type, AVFormatContext *s, int npixels) + uint8_t block_type, AVFormatContext *s) { uint8_t * vidbuf_start = NULL; int vidbuf_nbytes = 0; int code; int bytes_copied = 0; - int position; + int position, duration, npixels; unsigned int vidbuf_capacity; + int ret = 0; + AVStream *st; + + if (vid->video_index < 0) { + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + vid->video_index = st->index; + if (vid->audio_index < 0) { + av_log_ask_for_sample(s, "No audio packet before first video " + "packet. Using default video time base.\n"); + } + avpriv_set_pts_info(st, 64, 185, vid->sample_rate); + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = CODEC_ID_BETHSOFTVID; + st->codec->width = vid->width; + st->codec->height = vid->height; + } + st = s->streams[vid->video_index]; + npixels = st->codec->width * st->codec->height; vidbuf_start = av_malloc(vidbuf_capacity = BUFFER_PADDING_SIZE); if(!vidbuf_start) @@ -116,13 +128,15 @@ static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt, vidbuf_start[vidbuf_nbytes++] = block_type; - // get the video delay (next int16), and set the presentation time - vid->video_pts += vid->bethsoft_global_delay + avio_rl16(pb); + // get the current packet duration + duration = vid->bethsoft_global_delay + avio_rl16(pb); // set the y offset if it exists (decoder header data should be in data section) if(block_type == VIDEO_YOFF_P_FRAME){ - if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) + if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], 2) != 2) { + ret = AVERROR(EIO); goto fail; + } vidbuf_nbytes += 2; } @@ -138,8 +152,10 @@ static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt, if(block_type == VIDEO_I_FRAME) vidbuf_start[vidbuf_nbytes++] = avio_r8(pb); } else if(code){ // plain sequence - if(avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) + if (avio_read(pb, &vidbuf_start[vidbuf_nbytes], code) != code) { + ret = AVERROR(EIO); goto fail; + } vidbuf_nbytes += code; } bytes_copied += code & 0x7F; @@ -149,25 +165,37 @@ static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt, avio_seek(pb, -1, SEEK_CUR); break; } - if(bytes_copied > npixels) + if (bytes_copied > npixels) { + ret = AVERROR_INVALIDDATA; goto fail; + } } while(code); // copy data into packet - if(av_new_packet(pkt, vidbuf_nbytes) < 0) + if ((ret = av_new_packet(pkt, vidbuf_nbytes)) < 0) goto fail; memcpy(pkt->data, vidbuf_start, vidbuf_nbytes); av_free(vidbuf_start); pkt->pos = position; - pkt->stream_index = 0; // use the video decoder, which was initialized as the first stream - pkt->pts = vid->video_pts; + pkt->stream_index = vid->video_index; + pkt->duration = duration; + if (block_type == VIDEO_I_FRAME) + pkt->flags |= AV_PKT_FLAG_KEY; + + /* if there is a new palette available, add it to packet side data */ + if (vid->palette) { + uint8_t *pdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, + BVID_PALETTE_SIZE); + memcpy(pdata, vid->palette, BVID_PALETTE_SIZE); + av_freep(&vid->palette); + } vid->nframes--; // used to check if all the frames were read - return vidbuf_nbytes; + return 0; fail: av_free(vidbuf_start); - return -1; + return ret; } static int vid_read_packet(AVFormatContext *s, @@ -185,31 +213,54 @@ static int vid_read_packet(AVFormatContext *s, block_type = avio_r8(pb); switch(block_type){ case PALETTE_BLOCK: - avio_seek(pb, -1, SEEK_CUR); // include block type - ret_value = av_get_packet(pb, pkt, 3 * 256 + 1); - if(ret_value != 3 * 256 + 1){ - av_free_packet(pkt); + if (vid->palette) { + av_log(s, AV_LOG_WARNING, "discarding unused palette\n"); + av_freep(&vid->palette); + } + vid->palette = av_malloc(BVID_PALETTE_SIZE); + if (!vid->palette) + return AVERROR(ENOMEM); + if (avio_read(pb, vid->palette, BVID_PALETTE_SIZE) != BVID_PALETTE_SIZE) { + av_freep(&vid->palette); return AVERROR(EIO); } - pkt->stream_index = 0; - return ret_value; + return vid_read_packet(s, pkt); case FIRST_AUDIO_BLOCK: avio_rl16(pb); // soundblaster DAC used for sample rate, as on specification page (link above) - s->streams[1]->codec->sample_rate = 1000000 / (256 - avio_r8(pb)); - s->streams[1]->codec->bit_rate = s->streams[1]->codec->channels * s->streams[1]->codec->sample_rate * s->streams[1]->codec->bits_per_coded_sample; + vid->sample_rate = 1000000 / (256 - avio_r8(pb)); case AUDIO_BLOCK: + if (vid->audio_index < 0) { + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + vid->audio_index = st->index; + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_PCM_U8; + st->codec->channels = 1; + st->codec->bits_per_coded_sample = 8; + st->codec->sample_rate = vid->sample_rate; + st->codec->bit_rate = 8 * st->codec->sample_rate; + st->start_time = 0; + avpriv_set_pts_info(st, 64, 1, vid->sample_rate); + } audio_length = avio_rl16(pb); - ret_value = av_get_packet(pb, pkt, audio_length); - pkt->stream_index = 1; - return ret_value != audio_length ? AVERROR(EIO) : ret_value; + if ((ret_value = av_get_packet(pb, pkt, audio_length)) != audio_length) { + if (ret_value < 0) + return ret_value; + av_log(s, AV_LOG_ERROR, "incomplete audio block\n"); + return AVERROR(EIO); + } + pkt->stream_index = vid->audio_index; + pkt->duration = audio_length; + pkt->flags |= AV_PKT_FLAG_KEY; + return 0; case VIDEO_P_FRAME: case VIDEO_YOFF_P_FRAME: case VIDEO_I_FRAME: - return read_frame(vid, pb, pkt, block_type, s, - s->streams[0]->codec->width * s->streams[0]->codec->height); + return read_frame(vid, pb, pkt, block_type, s); case EOF_BLOCK: if(vid->nframes != 0) @@ -218,10 +269,18 @@ static int vid_read_packet(AVFormatContext *s, return AVERROR(EIO); default: av_log(s, AV_LOG_ERROR, "unknown block (character = %c, decimal = %d, hex = %x)!!!\n", - block_type, block_type, block_type); return -1; + block_type, block_type, block_type); + return AVERROR_INVALIDDATA; } } +static int vid_read_close(AVFormatContext *s) +{ + BVID_DemuxContext *vid = s->priv_data; + av_freep(&vid->palette); + return 0; +} + AVInputFormat ff_bethsoftvid_demuxer = { .name = "bethsoftvid", .long_name = NULL_IF_CONFIG_SMALL("Bethesda Softworks VID format"), @@ -229,4 +288,5 @@ AVInputFormat ff_bethsoftvid_demuxer = { .read_probe = vid_probe, .read_header = vid_read_header, .read_packet = vid_read_packet, + .read_close = vid_read_close, }; |