正在学习用ffmpeg写一个播放器,但是学习到tutorial3的时候播放视频没有声音,大家看看哪里出了问题啊
// Tutorial.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" extern "C" { #include"libavcodec\avcodec.h" #include"libavformat\avformat.h" #include "sdl\SDL.h" #include "sdl\SDL_thread.h" #include "libswscale\swscale.h" } #define SDL_AUDIO_BUFFER_SIZE 1024 #define MAX_AUDIO_FRAME_SIZE 192000 const char *VideoFile="e:\测试片源\1.mpeg"; int quit=0; typedef struct PacketQueue { AVPacketList *first_pkt,*last_pkt; int nb_packets; int size; SDL_mutex *mutex; SDL_cond *cond; }PacketQueue; PacketQueue audioq; void packet_queue_init(PacketQueue *q) { memset(q,0,sizeof(PacketQueue)); q->mutex=SDL_CreateMutex(); q->cond=SDL_CreateCond(); } int packet_queue_put(PacketQueue *q,AVPacket *pkt) { AVPacketList *pktl; if(av_dup_packet(pkt)<0) { printf("%s 存在问题",pkt); getchar(); return -1; } pktl=(AVPacketList *)av_malloc(sizeof(AVPacketList)); if(!pktl) { return -1; } pktl->pkt=*pkt; pktl->next=NULL; SDL_LockMutex(q->mutex); if(!q->last_pkt) { q->first_pkt=pktl; } else { q->last_pkt->next=pktl; } q->last_pkt=pktl; q->nb_packets++; q->size+=pktl->pkt.size; SDL_CondSignal(q->cond); SDL_UnlockMutex(q->mutex); return 0; } static int packet_queue_get(PacketQueue *q,AVPacket *pkt,int block) { AVPacketList *pktl; int ret; SDL_LockMutex(q->mutex); for(;;) { if(quit) { ret=-1; break; } pktl=q->first_pkt; if(pktl) { q->first_pkt=pktl->next; if(!q->first_pkt) { q->last_pkt=NULL; } q->nb_packets--; q->size-=pktl->pkt.size; *pkt=pktl->pkt; av_free(pktl); ret=1; break; } else { SDL_CondWait(q->cond,q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } int decode_interrupt_cb(void*) { return quit; } void SaveFrame(AVFrame *pFrame,int width,int height,int iFrame) { FILE *pFile; char szFilename[32]; int y; sprintf(szFilename,"frame %d.ppm",iFrame); pFile=fopen(szFilename,"wb"); if(pFile==NULL) { printf("储存失败"); getchar(); return; } fprintf(pFile,"P6\n%d %d\n255\n",width,height); for(y=0;y<height;y++) { fwrite(pFrame->data[0]+y*pFrame->linesize[0],1,width*3,pFile); } fclose(pFile); } int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf,int buf_size) { static AVPacket pkt; static uint8_t *audio_pkt_data = NULL; static int audio_pkt_size = 0; static AVFrame frame; int len1, data_size = 0; for (;;) { while (audio_pkt_size > 0) { int got_frame = 0; len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt); if (len1 < 0) { /* if error, skip frame */ audio_pkt_size = 0; break; } audio_pkt_data += len1; audio_pkt_size -= len1; if (got_frame) { data_size = frame.linesize[0]; /* data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, frame.nb_samples, aCodecCtx->sample_fmt, 1); */ memcpy(audio_buf, frame.data[0], data_size); } if (data_size <= 0) { /* No data yet, get more frames */ continue; } /* We have data, return it and come back for more later */ return data_size; } if (pkt.data) av_free_packet(&pkt); if (quit) { return -1; } if (packet_queue_get(&audioq, &pkt, 1) < 0) { return -1; } audio_pkt_data = pkt.data; audio_pkt_size = pkt.size; } return 0; } void audio_callback(void *userdata,uint8_t *stream,int len) { AVCodecContext *aCodecCtx=(AVCodecContext*)userdata; int len1,audio_size; static uint8_t audio_buf[(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(aCodecCtx,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_size,len1); len-=len1; stream+=len1; audio_buf_index+=len1; } } int _tmain(int argc, _TCHAR* argv[]) { SDL_Event event; av_register_all(); AVFormatContext *pFormatCtx=NULL; if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } if(avformat_open_input(&pFormatCtx,VideoFile,NULL,NULL)!=0) { printf("无法打开视频文件"); getchar(); return -1; } if(av_find_stream_info(pFormatCtx)<0) { printf("没有找到流信息"); getchar(); return -1; } static const AVIOInterruptCB int_cb={ decode_interrupt_cb, NULL}; pFormatCtx->interrupt_callback=int_cb; av_dump_format(pFormatCtx,0,VideoFile,0); int i,iVideoStream,iAudioStream; AVCodecContext *pCodecCtx=NULL; AVCodecContext *aCodecCtx=NULL; iVideoStream=-1; iAudioStream=-1; for(i=0;i<pFormatCtx->nb_streams;i++) { if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO&&iVideoStream<0) { iVideoStream=i; } if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO&&iAudioStream<0) { iAudioStream=i; } } if(-1==iVideoStream||-1==iAudioStream) { printf("没有找到视频流或音频流"); getchar(); return -1; } pCodecCtx=pFormatCtx->streams[iVideoStream]->codec; aCodecCtx=pFormatCtx->streams[iAudioStream]->codec; SDL_AudioSpec wanted_spec,spec; wanted_spec.freq=aCodecCtx->sample_rate; wanted_spec.format=AUDIO_S16SYS; wanted_spec.channels=aCodecCtx->channels; wanted_spec.silence=0; wanted_spec.samples=SDL_AUDIO_BUFFER_SIZE; wanted_spec.callback=audio_callback; wanted_spec.userdata=aCodecCtx; AVCodec *pCodec=NULL; AVCodec *aCodec=NULL; pCodec=avcodec_find_decoder(pCodecCtx->codec_id); aCodec=avcodec_find_decoder(aCodecCtx->codec_id); if(NULL==pCodec||NULL==aCodec) { printf("未能找到解码器"); getchar(); return -1; } if(SDL_OpenAudio(&wanted_spec,&spec)<0) { printf("SDL_OpenAudio:%s\n",SDL_GetError()); getchar(); return -1; } if(avcodec_open2(pCodecCtx,pCodec,NULL)<0||avcodec_open2(aCodecCtx,aCodec,NULL)<0) { printf("打开解码器失败"); getchar(); return -1; } AVFrame *pFrame=NULL; AVFrame *pFrameRGB=NULL; pFrame=avcodec_alloc_frame(); pFrameRGB=avcodec_alloc_frame(); if(NULL==pFrameRGB) { printf("分配储存失败"); getchar(); return -1; } uint8_t *buffer; int numBytes; numBytes=avpicture_get_size(PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height); buffer=(uint8_t*)av_malloc(numBytes*sizeof(uint8_t)); avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height); //////////////////////// SDL_Surface *screen=NULL; screen=SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,0,0); if(NULL==screen) { printf("SDL创建失败"); getchar(); return -1; } packet_queue_init(&audioq); SDL_PauseAudio(0); SDL_Overlay *bmp=NULL; bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen); SDL_Rect rect; struct SwsContext *img_convert_ctx; ///////////////////////////////////// int frameFinished=0; AVPacket packet; i=0; img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); while(av_read_frame(pFormatCtx,&packet)>=0) { if(packet.stream_index==iVideoStream) { avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet); if(frameFinished) { SDL_LockYUVOverlay(bmp); #if 0 AVPicture pict; pict.data[0]=bmp->pixels[0]; pict.data[1]=bmp->pixels[2]; pict.data[2]=bmp->pixels[1]; pict.linesize[0]=bmp->pitches[0]; pict.linesize[1]=bmp->pitches[2]; pict.linesize[2]=bmp->pitches[1]; #else bmp->pixels[0]=pFrameRGB->data[0]; bmp->pixels[2]=pFrameRGB->data[1]; bmp->pixels[1]=pFrameRGB->data[2]; bmp->pitches[0]=pFrameRGB->linesize[0]; bmp->pitches[2]=pFrameRGB->linesize[1]; bmp->pitches[1]=pFrameRGB->linesize[2]; #endif //转换图片为YUV格式 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); SDL_UnlockYUVOverlay(bmp); rect.x = 0; rect.y = 0; rect.w = pCodecCtx->width; rect.h = pCodecCtx->height; SDL_DisplayYUVOverlay(bmp, &rect); /*if(++i<=50) { SaveFrame(pFrameRGB,pCodecCtx->width,pCodecCtx->height,i); }*/ } } else if(packet.stream_index==iAudioStream) { packet_queue_put(&audioq,&packet); } else { av_free_packet(&packet); } } SDL_PollEvent(&event); switch(event.type) { case SDL_QUIT: quit=1; } av_free(buffer); av_free(pFrameRGB); av_free(pFrame); avcodec_close(pCodecCtx); av_close_input_file(pFormatCtx); getchar(); return 0; }
解决方案
40
在怀疑有问题的地方加写日志到文件。
有时不将“调用函数名字+各参数值,进入函数后各参数值,中间变量值,退出函数前准备返回的值,返回函数到调用处后函数名字+各参数值+返回值”这些信息写日志到文件中是无论怎么样也发现不了问题在哪里的,包括捕获各种异常、写日志到屏幕、单步或设断点或生成core文件、……这些方法都不行! 写日志到文件参考下面:
有时不将“调用函数名字+各参数值,进入函数后各参数值,中间变量值,退出函数前准备返回的值,返回函数到调用处后函数名字+各参数值+返回值”这些信息写日志到文件中是无论怎么样也发现不了问题在哪里的,包括捕获各种异常、写日志到屏幕、单步或设断点或生成core文件、……这些方法都不行! 写日志到文件参考下面:
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef WIN32 #include <windows.h> #include <io.h> #else #include <unistd.h> #include <sys/time.h> #include <pthread.h> #define CRITICAL_SECTION pthread_mutex_t #define _vsnprintf vsnprintf #endif //Log{ #define MAXLOGSIZE 20000000 #define MAXLINSIZE 16000 #include <time.h> #include <sys/timeb.h> #include <stdarg.h> char logfilename1[]="MyLog1.log"; char logfilename2[]="MyLog2.log"; static char logstr[MAXLINSIZE+1]; char datestr[16]; char timestr[16]; char mss[4]; CRITICAL_SECTION cs_log; FILE *flog; #ifdef WIN32 void Lock(CRITICAL_SECTION *l) { EnterCriticalSection(l); } void Unlock(CRITICAL_SECTION *l) { LeaveCriticalSection(l); } #else void Lock(CRITICAL_SECTION *l) { pthread_mutex_lock(l); } void Unlock(CRITICAL_SECTION *l) { pthread_mutex_unlock(l); } #endif void LogV(const char *pszFmt,va_list argp) { struct tm *now; struct timeb tb; if (NULL==pszFmt||0==pszFmt[0]) return; _vsnprintf(logstr,MAXLINSIZE,pszFmt,argp); ftime(&tb); now=localtime(&tb.time); sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday); sprintf(timestr,"%02d:%02d:%02d",now->tm_hour ,now->tm_min ,now->tm_sec ); sprintf(mss,"%03d",tb.millitm); printf("%s %s.%s %s",datestr,timestr,mss,logstr); flog=fopen(logfilename1,"a"); if (NULL!=flog) { fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr); if (ftell(flog)>MAXLOGSIZE) { fclose(flog); if (rename(logfilename1,logfilename2)) { remove(logfilename2); rename(logfilename1,logfilename2); } } else { fclose(flog); } } } void Log(const char *pszFmt,...) { va_list argp; Lock(&cs_log); va_start(argp,pszFmt); LogV(pszFmt,argp); va_end(argp); Unlock(&cs_log); } //Log} int main(int argc,char * argv[]) { int i; #ifdef WIN32 InitializeCriticalSection(&cs_log); #else pthread_mutex_init(&cs_log,NULL); #endif for (i=0;i<10000;i++) { Log("This is a Log %04d from FILE:%s LINE:%d\n",i, __FILE__, __LINE__); } #ifdef WIN32 DeleteCriticalSection(&cs_log); #else pthread_mutex_destroy(&cs_log); #endif return 0; } //1-78行添加到你带main的.c或.cpp的那个文件的最前面 //81-85行添加到你的main函数开头 //89-93行添加到你的main函数结束前 //在要写LOG的地方仿照第87行的写法写LOG到文件MyLog1.log中