开始光播放视频正常,但加上音频线程后,不但没有声音,而且连视频也卡在了一帧上,求教,谢谢~
videoplay.cpp
#include "videoplay.h"
videoplay::videoplay(){
pFormatContext = avformat_alloc_context();
pFrame = avcodec_alloc_frame();
pFrameRGB = avcodec_alloc_frame();
pktQueue = new packetQueue();
pktQueueAudio = new packetQueue();
}
void videoplay::reset(){
av_free(pFormatContext);
pFormatContext = avformat_alloc_context();
av_free(pFrame);
pFrame = avcodec_alloc_frame();
av_free(pFrameRGB);
pFrameRGB = avcodec_alloc_frame();
delete pktQueue;
packetQueue_init();
}
//打开视频文件,获取解码器
int videoplay::open_file(){
av_register_all();
if( avformat_open_input(&pFormatContext, path.c_str(), NULL, NULL )!=0 )
return -1;
if( av_find_stream_info(pFormatContext)<0 )
return -1;
av_dump_format(pFormatContext, 0, path.c_str(), 0);
videoStream = -1;
audioStream = -1;
for( unsigned int i=0;i<pFormatContext->nb_streams;i++ ){
if( pFormatContext->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO ){
videoStream = i;
}
else if( pFormatContext->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO ){
audioStream = i;
}
}
if( videoStream==-1 )
return -1;
if( audioStream==-1 )
return -1;
// video
pCodecContext = pFormatContext->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecContext->codec_id);
// audio
aCodecContext = pFormatContext->streams[audioStream]->codec;
aCodec = avcodec_find_decoder(aCodecContext->codec_id);
if( pCodec==NULL || aCodec==NULL )
return -1;
// video
if( avcodec_open2( pCodecContext, pCodec, NULL )<0 )
return -1;
ud *userdata = (ud*) malloc(sizeof(ud));
userdata->aCodecContext = aCodecContext;
userdata->vp = this;
// audio
wanted_spec = (SDL_AudioSpec*) av_mallocz(sizeof(SDL_AudioSpec));
wanted_spec->freq = aCodecContext->sample_rate;
wanted_spec->format = AUDIO_S16SYS;
wanted_spec->channels = aCodecContext->channels;
wanted_spec->silence = 0;
wanted_spec->samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec->callback = audio_callback;
wanted_spec->userdata = userdata;
if( SDL_OpenAudio(wanted_spec, NULL)<0 )
return -1;
av_free(pCodec);
av_free(aCodec);
}
//获取包,加入队列
int videoplay::getPackets(){
int numBytes;
packetQueue_init();
pFrame = avcodec_alloc_frame();
pFrameRGB = avcodec_alloc_frame();
if( pFrame==NULL || pFrameRGB==NULL )
return -1;
numBytes = avpicture_get_size( PIX_FMT_RGB24, pCodecContext->width, pCodecContext->height );
buffer = (uint8_t*)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill( (AVPicture*)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecContext->width, pCodecContext->height );
AVPacket packet;
while( av_read_frame(pFormatContext, &packet)>=0 ){
if( packet.stream_index==videoStream )
packetQueue_put( pktQueue, &packet );
if( packet.stream_index==audioStream )
packetQueue_put( pktQueueAudio, &packet );
}
av_free(pCodecContext);
}
void videoplay::packetQueue_init(){
pktQueue = (packetQueue*)malloc(sizeof(packetQueue));
memset( pktQueue, 0, sizeof(packetQueue) );
pktQueue->mutex = SDL_CreateMutex();
pktQueue->cond = SDL_CreateCond();
pktQueueAudio = (packetQueue*)malloc(sizeof(packetQueue));
memset( pktQueueAudio, 0, sizeof(packetQueue) );
pktQueueAudio->mutex = SDL_CreateMutex();
pktQueueAudio->cond = SDL_CreateCond();
}
bool videoplay::packetQueue_get(packetQueue *pktQueue, AVPacket *packet){
int ret = 0; //quit=0;
AVPacketList *pkt1;
SDL_LockMutex(pktQueue->mutex);
if(pktQueue->nb_packets<=VIDEO_BUFFER_MIN_SIZE){
SDL_CondSignal(pktQueue->cond);
}
while(1)
{
pkt1=pktQueue->first;
if(pkt1)
{
pktQueue->first=pkt1->next;
if(!pktQueue->first)pktQueue->last=NULL;
pktQueue->nb_packets--;
*packet = pkt1->pkt;
av_free(pkt1);
ret=1;
break;
}
else
{
SDL_CondWait(pktQueue->cond,pktQueue->mutex);
}
}
SDL_UnlockMutex(pktQueue->mutex);
return ret;
}
//往队列加包
void videoplay::packetQueue_put(packetQueue pktQueue, AVPacket *packet){
AVPacketList *pkt1=(AVPacketList)av_malloc(sizeof(AVPacketList));
pkt1->pkt=*packet;
pkt1->next=NULL;
SDL_LockMutex( pktQueue->mutex);
if( pktQueue->nb_packets>=VIDEO_BUFFER_MAX_SIZE ){
SDL_CondWait( pktQueue->cond, pktQueue->mutex );
}
if(!pktQueue->last)
pktQueue->first=pkt1;
else
pktQueue->last->next=pkt1;
pktQueue->last=pkt1;
pktQueue->nb_packets++;
if( pktQueue->nb_packets>=VIDEO_BUFFER_MIN_SIZE ){
SDL_CondSignal(pktQueue->cond);
}
SDL_CondSignal(pktQueue->cond);
SDL_UnlockMutex(pktQueue->mutex);
return ;
}
QImage* videoplay::play(QImage &image){
AVPacket *packet = new AVPacket();
struct SwsContext *pSwsCtx;
int frameFinished;
while( packetQueue_get( pktQueue, packet) ){
avcodec_decode_video2( pCodecContext, pFrame, &frameFinished, packet );
if( frameFinished ){
pSwsCtx = sws_getContext( pCodecContext->width, pCodecContext->height,pCodecContext->pix_fmt, pCodecContext->width,
pCodecContext->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL );
sws_scale (pSwsCtx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecContext->height, pFrameRGB->data, pFrameRGB->linesize);
bmp->pixels[0] = pFrameRGB->data[0];
bmp->pixels[1] = pFrameRGB->data[2];
bmp->pixels[2] = pFrameRGB->data[1];
bmp->pitches[0] = pFrameRGB->linesize[0];
bmp->pitches[1] = pFrameRGB->linesize[2];
bmp->pitches[2] = pFrameRGB->linesize[1];
SDL_UnlockYUVOverlay(bmp);
rect.x=0;
rect.y=0;
rect.w=pCodecContext->width;
rect.h=pCodecContext->height;
SDL_DisplayYUVOverlay(bmp,&rect); */
memcpy( buffer,pFrameRGB,sizeof(AVFrame) );
QImage tmpImage( (uchar*)buffer, pCodecContext->width, pCodecContext->height, QImage::Format_RGB888 );
image = tmpImage.copy();
SDL_Delay(40);
int i = 0;
return ℑ
}
}
return NULL;
}
int videoplay::audio_decode_frame( videoplay *vp, AVCodecContext *aCodecContext, Uint8 *audio_buf, int buf_size ){
static AVPacket pkt;
static Uint8 *audio_pkt_data = NULL;
static int audio_pkt_size = 0;
int len_1, data_size;
while(1){
while(audio_pkt_size>0){
data_size = buf_size;
len_1 = avcodec_decode_audio3( aCodecContext, (int16_t*)audio_buf, &data_size, &pkt);
if( len_1<0 ){
audio_pkt_size = 0;
break;
}
audio_pkt_data = audio_pkt_data + len_1;
audio_pkt_size = audio_pkt_size - len_1;
if( data_size<=0 )
continue;
return data_size;
}
if(pkt.data)
av_free_packet(&pkt);
if( vp->packetQueue_get(vp->pktQueueAudio, &pkt)==0 )
return -1;
audio_pkt_data = pkt.data;
audio_pkt_size = pkt.size;
}
}
void videoplay::audio_callback( void*userdata, Uint8 stream, int len ){
ud *udata = (ud)userdata;
AVCodecContext *aCodecContext = udata->aCodecContext;
videoplay *vp = udata->vp;
int len_1, audio_size;
static Uint8 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( vp, aCodecContext, 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;
}
}
len_1 = audio_buf_size - audio_buf_index;
if( len_1>len )
len_1 = len;
// memcpy( stream, (Uint8*)audio_buf+audio_buf_index, len_1 );
SDL_MixAudio(stream,(Uint8*)audio_buf+audio_buf_index, len_1, SDL_MIX_MAXVOLUME );
len = len - len_1;
stream = stream + len_1;
audio_buf_index = audio_buf_index + len_1;
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include "videoplay.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect( this, SIGNAL(readOneFrame(QPixmap)), this, SLOT(setPic(QPixmap)) );
}
MainWindow::~MainWindow()
{
delete ui;
}
int threadFunc( void arg){
videoplay *vp = (videoplay)arg;
vp->getPackets();
return 1;
}
int MainWindow::threadFunc_1( void arg){
MainWindow *mainWindow = (MainWindow)arg;
QImage *image = new QImage();
while( mainWindow->vp.play(*image) ){
QPixmap pixmap = QPixmap::fromImage(image->scaled(mainWindow->ui->label->size(), Qt::KeepAspectRatio));
emit mainWindow->readOneFrame(pixmap);
Sleep(1);
mainWindow->state = 1;
}
delete image;
return 1;
}
int threadFunc_2( void *arg){
while(1)
SDL_PauseAudio(5);
return 1;
}
void MainWindow::closeEvent(QCloseEvent *event){
SDL_KillThread(decodeTid);
SDL_KillThread(videoTid);
SDL_KillThread(audioTid);
}
void MainWindow::on_pushButton_clicked() //打开,获取到视频文件路径 path
{
vp.reset();
QFileDialog* fileDialog = new QFileDialog(this);
QString path = fileDialog->getOpenFileName(this, "打开", ".", "Video Files(*.mp4 .avi,*rmvb);;all()", 0, 0);
decodeTid=NULL;
videoTid=NULL;
if( path.length()!=0 ){
if( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) )
return ;
ui->label->setText( path );
vp.setPath(path.toStdString());
vp.open_file();
decodeTid = SDL_CreateThread(threadFunc,&vp);
videoTid = SDL_CreateThread(threadFunc_1,this);
SDL_PauseAudio(0);
audioTid = SDL_CreateThread(threadFunc_2,NULL);
}
}
void MainWindow::on_pushButton_2_clicked() //快退
{
}
void MainWindow::on_pushButton_3_clicked() //播放/停止
{
if( state==1 ){ //点击后暂停
ui->pushButton_3->setText(tr("暂停"));
state = 0;
}
else{
ui->pushButton_3->setText(tr("播放")); //点击后播放
state = 1;
}
}
void MainWindow::on_pushButton_4_clicked() //快进
{
}
void MainWindow::setPic(QPixmap pixmap){
ui->label->setPixmap(pixmap);
ui->label->repaint();
}