u012562203 2015-06-30 06:14
浏览 2857

关于SDL音频播放没声音的问题~

开始光播放视频正常,但加上音频线程后,不但没有声音,而且连视频也卡在了一帧上,求教,谢谢~

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 &image;
    }
}
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();
}

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
    • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
    • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
    • ¥15 帮我写一个c++工程
    • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
    • ¥15 关于smbclient 库的使用
    • ¥15 微信小程序协议怎么写
    • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
    • ¥20 怎么用dlib库的算法识别小麦病虫害
    • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启