在手册中,这部分有的没有翻译。
流程大致是这样的:
main-->定时器产生FF_REFRESH_EVENT事件-->产生decode_thread线程-->进入SDL事件循环
decode_thread-->初始化操作(很简单的找到解码库等)-->read包-->将包放入相应的队列中-->如果是视频流调用video_thread -->如果是音频流则设置audio_callback
video_thread-->取包-->解码-->解码后的AVFrame送去PictQ等待事件触发去读取它
audio_callback-->取包-->解码
video_refresh_timer(响应FF_REFRESH_EVENT)-->设置80毫秒之后的定时-->video_display显示
代码如下。在看手册的过程中发现很多问题 大家可以一起交流
- int main()
- {
- file=fopen("123.txt","wb");
- av_register_all();
- //初始化ffmpeg库
- SDL_Event event;
- VideoState *is;
- is= (VideoState*)av_mallocz(sizeof(VideoState));
- strncpy(is->filename,FILENAME, sizeof(is->filename));
- // 初始化显示互斥
- is->pictq_mutex=SDL_CreateMutex();
- is->pictq_cond=SDL_CreateCond();
- //初始化SDL库
- SDL_Init(SDL_INIT_AUDIO|SDL_INIT_TIMER|SDL_INIT_VIDEO);
- SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
- SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
- SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
- SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
- //添加定时器
- schedule_refresh(is,40);
- is->parse_tid=SDL_CreateThread(decode_thread,is);
- if (!is->parse_tid)
- {
- av_free(is);
- return -1;
- }
- event_loop();
- return 0;
- }
以上是main函数。
下面贴出音频部分代码:
- void audio_callback(void *userdata, Uint8 *stream, int len)
- {
- VideoState* is=(VideoState*) userdata;
- int len1;
- int audio_size;
- static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE*3)/2];
- static unsigned int audio_buf_size=0;
- static unsigned int audio_buf_index=0;
- while (len>0)
- {
- if (audio_buf_index>=audio_buf_size)
- {
- audio_size= audio_decode_frame(is,audio_buf,
- sizeof(audio_buf));
- if (audio_size<0)
- {
- audio_buf_size=1024;
- memset(audio_buf,0,audio_buf_size);
- }
- else
- {
- audio_buf_size=audio_size;
- }
- audio_buf_index=0;
- }
- len1=audio_buf_size-audio_buf_index;
- if (len1>len)
- {
- len1=len;
- }
- memcpy(stream,(uint8_t*)audio_buf+audio_buf_index,len1);
- len-=len1;
- stream+=len1;
- audio_buf_index+=len1;
- }
- }
- int audio_decode_frame(VideoState* is, uint8_t* audio_buf, int buf_size)
- {
- AVCodecContext* paCodecCtx=is->audio_st->codec;
- // puts("yanxinmeng ' thread");
- static AVPacket pkt;
- static uint8_t * audio_pkt_data =NULL;
- static int audio_pkt_size=0;
- int len1, data_size;
- for (;;)
- {
- while(audio_pkt_size>0)
- {
- data_size=buf_size;
- len1= avcodec_decode_audio2(paCodecCtx, (int16_t*) audio_buf,
- &data_size, audio_pkt_data,audio_pkt_size);
- if (len1<0)
- {
- audio_pkt_size=0;
- break;
- }
- audio_pkt_data+=len1;
- audio_pkt_size-=len1;
- if (data_size<=0)
- {
- continue;
- }
- return data_size;
- }
- if(pkt.data)
- av_free_packet(&pkt);
- if (quit)
- {
- return -1;
- }
- if (packet_queue_get(&(is->audioq),&pkt,1)<0)
- {
- return -1;
- }
- audio_pkt_data= pkt.data;
- audio_pkt_size=pkt.size;
- }
- }
以下是视频处理部分
- int video_thread(void* arg)
- {
- VideoState * is=(VideoState*) arg;
- AVPacket pkt1;
- AVPacket* packet = & pkt1;
- int len1, frameFinished;
- AVFrame *pFrame;
- //分配好解码后的frame
- pFrame = avcodec_alloc_frame();
- screen =SDL_SetVideoMode(is->video_st->codec->width,
- is->video_st->codec->height,0,0);
- for (;;)
- {
- if (packet_queue_get(&is->videoq,packet,1)<0)
- {
- break;
- }
- len1 = avcodec_decode_video(is->video_st->codec, pFrame,&frameFinished,
- packet->data,packet->size);
- if (frameFinished)
- {
- //解码完成将帧队列化
- if (queue_picture(is,pFrame)<0)
- {
- break;
- }
- }
- av_free_packet(packet);
- }
- av_free(pFrame);
- return 0;
- }
- //把帧队列化
- int queue_picture(VideoState* is, AVFrame* pFrame)
- {
- VideoPicture * vp;
- int dst_pix_mt;
- AVPicture pict;
- SDL_LockMutex(is->pictq_mutex);
- while (is->pictq_size>= VIDEO_PICTURE_QUEUE_SIZE&& !is->quit)
- {
- SDL_CondWait(is->pictq_cond, is->pictq_mutex);
- }
- SDL_UnlockMutex(is->pictq_mutex);
- if(is->quit) return -1;
- vp= &is->pictq[is->pictq_windex];//写指针
- if (!vp->bmp||vp->width!= is->video_st->codec->width
- || vp->height!= is->video_st->codec->height)
- {
- SDL_Event event;
- vp->allocated=0;
- event.type =FF_ALLOC_EVENT;
- event.user.data1=is;
- SDL_PushEvent(&event);
- SDL_LockMutex(is->pictq_mutex);
- while (!vp->allocated&&!is->quit)
- {
- SDL_CondWait(is->pictq_cond,is->pictq_mutex);
- }
- SDL_UnlockMutex(is->pictq_mutex);
- if (is->quit)
- {
- return -1;
- }
- }
- if ( vp->bmp)
- {
- SDL_LockYUVOverlay(vp->bmp);
- dst_pix_mt= PIX_FMT_YUV420P;
- pict.data[0]= vp->bmp->pixels[0];
- pict.data[1]= vp->bmp->pixels[2];
- pict.data[2]= vp->bmp->pixels[1];
- pict.linesize[0]= vp->bmp->pitches[0];
- pict.linesize[1]= vp->bmp->pitches[2];
- pict.linesize[2]= vp->bmp->pitches[1];
- static SwsContext* img_convert_ctx;
- img_convert_ctx=sws_getCachedContext(img_convert_ctx,vp->width,vp->height,is->video_st->codec->pix_fmt,
- vp->width,vp->height,PIX_FMT_YUV420P,SWS_BICUBIC,NULL,NULL,NULL);
- sws_scale(img_convert_ctx,pFrame->data,pFrame->linesize,0,
- vp->height,pict.data,pict.linesize);
- SDL_LockYUVOverlay(vp->bmp);
- if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
- {
- is->pictq_windex=0;
- }
- SDL_LockMutex(is->pictq_mutex);
- is->pictq_size++;
- SDL_UnlockMutex(is->pictq_mutex);
- }
- return 0;
- }
基本结构是这样 事件循环就不贴了。很简单的。