Mercurial > libavformat.hg
view ogg.c @ 584:4e3bab6555ae libavformat
When playing
ftp://ftp.mplayerhq.hu/MPlayer/samples/V-codecs/QPEG/VWbig6.avi with my
decoder (should appear soon) it hadn't changed palette even there are
palette change chunks in that AVI.
Here is small patch to make it work (zero number of colors to change in
that chunk actually means to change ALL colors).
patch by (Kostya <cannonball>at<bw-team>dot<com>)
author | michael |
---|---|
date | Fri, 12 Nov 2004 01:32:35 +0000 |
parents | 6e685aedef2e |
children | fe24632a577b |
line wrap: on
line source
/* * Ogg bitstream support * Mark Hills <mark@pogo.org.uk> * * Uses libogg, but requires libvorbisenc to construct correct headers * when containing Vorbis stream -- currently the only format supported */ #include <stdio.h> #include <ogg/ogg.h> #include "avformat.h" #undef NDEBUG #include <assert.h> #define DECODER_BUFFER_SIZE 4096 typedef struct OggContext { /* output */ ogg_stream_state os ; int header_handled ; ogg_packet op; /* input */ ogg_sync_state oy ; } OggContext ; #ifdef CONFIG_ENCODERS static int ogg_write_header(AVFormatContext *avfcontext) { OggContext *context = avfcontext->priv_data; ogg_packet *op= &context->op; int n, i; ogg_stream_init(&context->os, 31415); for(n = 0 ; n < avfcontext->nb_streams ; n++) { AVCodecContext *codec = &avfcontext->streams[n]->codec; uint8_t *p= codec->extradata; av_set_pts_info(avfcontext->streams[n], 60, 1, AV_TIME_BASE); for(i=0; i < codec->extradata_size; i+= op->bytes){ op->bytes = p[i++]<<8; op->bytes+= p[i++]; op->packet= &p[i]; op->b_o_s= op->packetno==0; ogg_stream_packetin(&context->os, op); op->packetno++; //FIXME multiple streams } context->header_handled = 0 ; } return 0 ; } static int ogg_write_packet(AVFormatContext *avfcontext, AVPacket *pkt) { OggContext *context = avfcontext->priv_data ; AVCodecContext *avctx= &avfcontext->streams[pkt->stream_index]->codec; ogg_packet *op= &context->op; ogg_page og ; int64_t pts; pts= av_rescale(pkt->pts, avctx->sample_rate, AV_TIME_BASE); // av_log(avfcontext, AV_LOG_DEBUG, "M%d\n", size); /* flush header packets so audio starts on a new page */ if(!context->header_handled) { while(ogg_stream_flush(&context->os, &og)) { put_buffer(&avfcontext->pb, og.header, og.header_len) ; put_buffer(&avfcontext->pb, og.body, og.body_len) ; put_flush_packet(&avfcontext->pb); } context->header_handled = 1 ; } op->packet = (uint8_t*) pkt->data; op->bytes = pkt->size; op->b_o_s = op->packetno == 0; op->granulepos= pts; /* correct the fields in the packet -- essential for streaming */ ogg_stream_packetin(&context->os, op); while(ogg_stream_pageout(&context->os, &og)) { put_buffer(&avfcontext->pb, og.header, og.header_len); put_buffer(&avfcontext->pb, og.body, og.body_len); put_flush_packet(&avfcontext->pb); } op->packetno++; return 0; } static int ogg_write_trailer(AVFormatContext *avfcontext) { OggContext *context = avfcontext->priv_data ; ogg_page og ; while(ogg_stream_flush(&context->os, &og)) { put_buffer(&avfcontext->pb, og.header, og.header_len) ; put_buffer(&avfcontext->pb, og.body, og.body_len) ; put_flush_packet(&avfcontext->pb); } ogg_stream_clear(&context->os) ; return 0 ; } static AVOutputFormat ogg_oformat = { "ogg", "Ogg Vorbis", "audio/x-vorbis", "ogg", sizeof(OggContext), CODEC_ID_VORBIS, 0, ogg_write_header, ogg_write_packet, ogg_write_trailer, } ; #endif //CONFIG_ENCODERS static int next_packet(AVFormatContext *avfcontext, ogg_packet *op) { OggContext *context = avfcontext->priv_data ; ogg_page og ; char *buf ; while(ogg_stream_packetout(&context->os, op) != 1) { /* while no pages are available, read in more data to the sync */ while(ogg_sync_pageout(&context->oy, &og) != 1) { buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) return 1 ; ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; } /* got a page. Feed it into the stream and get the packet */ if(ogg_stream_pagein(&context->os, &og) != 0) return 1 ; } return 0 ; } static int ogg_read_header(AVFormatContext *avfcontext, AVFormatParameters *ap) { OggContext *context = avfcontext->priv_data; ogg_packet op ; char *buf ; ogg_page og ; AVStream *ast ; AVCodecContext *codec; uint8_t *p; int i; ogg_sync_init(&context->oy) ; buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) return AVERROR_IO ; ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; ogg_sync_pageout(&context->oy, &og) ; ogg_stream_init(&context->os, ogg_page_serialno(&og)) ; ogg_stream_pagein(&context->os, &og) ; /* currently only one vorbis stream supported */ ast = av_new_stream(avfcontext, 0) ; if(!ast) return AVERROR_NOMEM ; av_set_pts_info(ast, 60, 1, AV_TIME_BASE); codec= &ast->codec; codec->codec_type = CODEC_TYPE_AUDIO; codec->codec_id = CODEC_ID_VORBIS; for(i=0; i<3; i++){ if(next_packet(avfcontext, &op)){ return -1; } codec->extradata_size+= 2 + op.bytes; codec->extradata= av_realloc(codec->extradata, codec->extradata_size); p= codec->extradata + codec->extradata_size - 2 - op.bytes; *(p++)= op.bytes>>8; *(p++)= op.bytes&0xFF; memcpy(p, op.packet, op.bytes); } return 0 ; } static int ogg_read_packet(AVFormatContext *avfcontext, AVPacket *pkt) { ogg_packet op ; if(next_packet(avfcontext, &op)) return AVERROR_IO ; if(av_new_packet(pkt, op.bytes) < 0) return AVERROR_IO ; pkt->stream_index = 0 ; memcpy(pkt->data, op.packet, op.bytes); if(avfcontext->streams[0]->codec.sample_rate && op.granulepos!=-1) pkt->pts= av_rescale(op.granulepos, AV_TIME_BASE, avfcontext->streams[0]->codec.sample_rate); // printf("%lld %d %d\n", pkt->pts, (int)op.granulepos, avfcontext->streams[0]->codec.sample_rate); return op.bytes; } static int ogg_read_close(AVFormatContext *avfcontext) { OggContext *context = avfcontext->priv_data ; ogg_stream_clear(&context->os) ; ogg_sync_clear(&context->oy) ; av_freep(&avfcontext->streams[0]->codec.extradata); return 0 ; } static AVInputFormat ogg_iformat = { "ogg", "Ogg Vorbis", sizeof(OggContext), NULL, ogg_read_header, ogg_read_packet, ogg_read_close, .extensions = "ogg", } ; int ogg_init(void) { #ifdef CONFIG_ENCODERS av_register_output_format(&ogg_oformat) ; #endif av_register_input_format(&ogg_iformat); return 0 ; }