// ref: http://ffmpeg.org/doxygen/trunk/avio_reading_8c-example.html// ref: http://ffmpeg.org/doxygen/trunk/demuxing_decoding_8c-example.html extern"C"{#include<libavcodec/avcodec.h>#include<libavformat/avformat.h>#include<libavformat/avio.h>#include<libavutil/file.h>#include<libavutil/imgutils.h>#include<libavutil/samplefmt.h>#include<libavutil/timestamp.h>}#include<iostream>// std::cout#include<thread>// std::threadstatic AVFormatContext *fmt_ctx =NULL;static AVCodecContext *video_dec_ctx =NULL;staticint width, height;staticenumAVPixelFormat pix_fmt;static AVStream *video_stream =NULL;staticconstchar*src_filename =NULL;staticconstchar*video_dst_filename =NULL;static FILE *video_dst_file =NULL;staticuint8_t*video_dst_data[4]={NULL};staticint video_dst_linesize[4];staticint video_dst_bufsize;staticint video_stream_idx =-1;static AVFrame *frame =NULL;static AVPacket pkt;staticint video_frame_count =0;#defineAVIO_BUFFER_SIZE32*1024staticintopen_codec_context(int*stream_idx,
AVCodecContext **dec_ctx, AVFormatContext *fmt_ctx,enumAVMediaType type){int ret, stream_index;
AVStream *st;
AVCodec *dec =NULL;
AVDictionary *opts =NULL;
ret =av_find_best_stream(fmt_ctx, type,-1,-1,NULL,0);if(ret <0){fprintf(stderr,"Could not find %s stream in input file '%s'\n",av_get_media_type_string(type), src_filename);return ret;}else{
stream_index = ret;
st = fmt_ctx->streams[stream_index];/* find decoder for the stream */
dec =avcodec_find_decoder(st->codecpar->codec_id);if(!dec){fprintf(stderr,"Failed to find %s codec\n",av_get_media_type_string(type));returnAVERROR(EINVAL);}/* Allocate a codec context for the decoder */*dec_ctx =avcodec_alloc_context3(dec);if(!*dec_ctx){fprintf(stderr,"Failed to allocate the %s codec context\n",av_get_media_type_string(type));returnAVERROR(ENOMEM);}/* Copy codec parameters from input stream to output codec context */if((ret =avcodec_parameters_to_context(*dec_ctx, st->codecpar))<0){fprintf(stderr,"Failed to copy %s codec parameters to decoder context\n",av_get_media_type_string(type));return ret;}/* Init the decoders */if((ret =avcodec_open2(*dec_ctx, dec,&opts))<0){fprintf(stderr,"Failed to open %s codec\n",av_get_media_type_string(type));return ret;}*stream_idx = stream_index;}return0;}staticintoutput_video_frame(AVFrame *frame){if(frame->width != width || frame->height != height ||
frame->format != pix_fmt){/* To handle this change, one could call av_image_alloc again and
* decode the following frames into another rawvideo file. */fprintf(stderr,"Error: Width, height and pixel format have to be ""constant in a rawvideo file, but the width, height or ""pixel format of the input video changed:\n""old: width = %d, height = %d, format = %s\n""new: width = %d, height = %d, format = %s\n",
width, height,av_get_pix_fmt_name(pix_fmt),
frame->width, frame->height,av_get_pix_fmt_name((AVPixelFormat)frame->format));return-1;}printf("video_frame n:%d coded_n:%d\n",
video_frame_count++, frame->coded_picture_number);/* copy decoded frame to destination buffer:
* this is required since rawvideo expects non aligned data */av_image_copy(video_dst_data, video_dst_linesize,(constuint8_t**)(frame->data), frame->linesize,
pix_fmt, width, height);/* write to rawvideo file */fwrite(video_dst_data[0],1, video_dst_bufsize, video_dst_file);return0;}staticintdecode_packet(AVCodecContext *dec,const AVPacket *pkt){int ret =0;// submit the packet to the decoder
ret =avcodec_send_packet(dec, pkt);if(ret <0){fprintf(stderr,"Error submitting a packet for decoding (%d)\n", ret);return ret;}// get all the available frames from the decoderwhile(ret >=0){
ret =avcodec_receive_frame(dec, frame);if(ret <0){// those two return values are special and mean there is no output// frame available, but there were no errors during decodingif(ret == AVERROR_EOF || ret ==AVERROR(EAGAIN))return0;fprintf(stderr,"Error during decoding (%d)\n", ret);return ret;}// write the frame data to output fileif(dec->codec->type == AVMEDIA_TYPE_VIDEO)
ret =output_video_frame(frame);av_frame_unref(frame);if(ret <0)return ret;}return0;}structbuffer_data{uint8_t*ptr;
size_t size;///< size left in the bufferint index;// 自定义添加};staticintread_packet(void*opaque,uint8_t*buf,int buf_size){
std::thread::id t_id = std::this_thread::get_id();structbuffer_data*bd =(structbuffer_data*)opaque;
buf_size =FFMIN(buf_size, bd->size);if(!buf_size)return AVERROR_EOF;printf("ptr:%p size:%zu pid:%d index:%d\n ", bd->ptr, bd->size, t_id, bd->index);/* copy internal buffer data to buf */memcpy(buf, bd->ptr, buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;return buf_size;}// index为自定义添加,为了做标识inttest_avio_reading(char*filename,int index){
AVFormatContext *fmt_ctx =NULL;
AVIOContext *avio_ctx =NULL;uint8_t*buffer =NULL,*avio_ctx_buffer =NULL;
size_t buffer_size, avio_ctx_buffer_size = AVIO_BUFFER_SIZE;char*input_filename =NULL;int ret =0;structbuffer_data bd ={0};
input_filename = filename;/* slurp file content into buffer */
ret =av_file_map(input_filename,&buffer,&buffer_size,0,NULL);if(ret <0)goto end;/* fill opaque structure used by the AVIOContext read callback */
bd.ptr = buffer;
bd.size = buffer_size;
bd.index = index;if(!(fmt_ctx =avformat_alloc_context())){
ret =AVERROR(ENOMEM);goto end;}
avio_ctx_buffer =(uint8_t*)av_malloc(avio_ctx_buffer_size);if(!avio_ctx_buffer){
ret =AVERROR(ENOMEM);goto end;}
avio_ctx =avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,0,&bd,&read_packet,NULL,NULL);if(!avio_ctx){
ret =AVERROR(ENOMEM);goto end;}
fmt_ctx->pb = avio_ctx;
ret =avformat_open_input(&fmt_ctx,NULL,NULL,NULL);if(ret <0){fprintf(stderr,"Could not open input\n");goto end;}
ret =avformat_find_stream_info(fmt_ctx,NULL);if(ret <0){fprintf(stderr,"Could not find stream information\n");goto end;}av_dump_format(fmt_ctx,0, input_filename,0);if(open_codec_context(&video_stream_idx,&video_dec_ctx, fmt_ctx, AVMEDIA_TYPE_VIDEO)>=0){
video_stream = fmt_ctx->streams[video_stream_idx];
video_dst_file =fopen(video_dst_filename,"wb");if(!video_dst_file){fprintf(stderr,"Could not open destination file %s\n", video_dst_filename);
ret =1;goto end;}/* allocate image where the decoded image will be put */
width = video_dec_ctx->width;
height = video_dec_ctx->height;
pix_fmt = video_dec_ctx->pix_fmt;
ret =av_image_alloc(video_dst_data, video_dst_linesize,
width, height, pix_fmt,1);if(ret <0){fprintf(stderr,"Could not allocate raw video buffer\n");goto end;}
video_dst_bufsize = ret;}
frame =av_frame_alloc();if(!frame){fprintf(stderr,"Could not allocate frame\n");
ret =AVERROR(ENOMEM);goto end;}/* initialize packet, set data to NULL, let the demuxer fill it */av_init_packet(&pkt);
pkt.data =NULL;
pkt.size =0;if(video_stream)printf("Demuxing video from file '%s' into '%s'\n", src_filename, video_dst_filename);/* read frames from the file */while(av_read_frame(fmt_ctx,&pkt)>=0){// check if the packet belongs to a stream we are interested in, otherwise// skip itif(pkt.stream_index == video_stream_idx)
ret =decode_packet(video_dec_ctx,&pkt);av_packet_unref(&pkt);if(ret <0)break;}/* flush the decoders */if(video_dec_ctx)decode_packet(video_dec_ctx,NULL);printf("Demuxing succeeded.\n");if(video_stream){printf("Play the output video file with the command:\n""ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",av_get_pix_fmt_name(pix_fmt), width, height,
video_dst_filename);}
end:avformat_close_input(&fmt_ctx);/* note: the internal buffer could have changed, and be != avio_ctx_buffer */if(avio_ctx)av_freep(&avio_ctx->buffer);avio_context_free(&avio_ctx);av_file_unmap(buffer, buffer_size);if(ret <0){fprintf(stderr,"Error occurred: %d\n", ret);return1;}return0;}intmain(int argc,char*argv[]){char*input_filename =NULL;if(argc <2){fprintf(stderr,"usage: %s input_file\n""API example program to show how to read from a custom buffer ""accessed through AVIOContext.\n", argv[0]);return1;}
input_filename = argv[1];
video_dst_filename = argv[2];
std::thread first(test_avio_reading, input_filename,11);
std::cout <<"first t_id"<< first.get_id()<< std::endl;
first.join();return0;}