Code Bye

ffmpeg tutorial3播放视频没有声音

正在学习用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文件、……这些方法都不行! 写日志到文件参考下面:
#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中

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明ffmpeg tutorial3播放视频没有声音