QT 播放mp4

QQ:609162385

这里写图片描述

#include "myffmpeg.h"


list<AVFrame*> audioList ;
struct SwrContext  *au_convert_ctx;

uint8_t * out_buffer;
uint8_t * out_buffer_a;

int out_buffer_size_A;


#define MAX_AUDIO_FRAME_SIZE 192000
MyFFmpeg::MyFFmpeg()
{
    cout<<__FUNCTION__<<__LINE__<<endl;
    av_register_all();
    avformat_network_init();
}

MyFFmpeg::~MyFFmpeg()
{
    avformat_free_context(pFormatCtx);
    avformat_network_deinit();
}

bool MyFFmpeg::OpenUrl()
{



    //    cout<<__FUNCTION__<<__LINE__<<endl;
    //this->filename = filepath;
    pFormatCtx = avformat_alloc_context();
    cout<<"the file is:"<<filename.c_str()<<endl;
    if (avformat_open_input(&pFormatCtx, filename.c_str(), NULL, NULL) != 0) {
        printf("can't open the file. \n");
        return false;
    }
    //  cout<<__FUNCTION__<<__LINE__<<endl;
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        printf("Could't find stream infomation.\n");
        return false;
    }
    //  cout<<__FUNCTION__<<__LINE__<<endl;
    videoStream = -1;
    audioStream = -1;
    dataStream = -1;
    for (int i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
        }
        else if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioStream = i;
        }
        else if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_DATA)
        {
            dataStream = i;
        }

    }
    if (videoStream == -1) {
        printf("Didn't find a video stream.\n");
    }
    if (audioStream == -1) {
        printf("Didn't find a audio Stream.\n");
    }
    if (dataStream == -1) {
        printf("Didn't find a data Stream.\n");
    }

    ///查找解码器
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    //cout<<__FUNCTION__<<__LINE__<<endl;
    if (pCodec == NULL) {
        printf("Codec not found.\n");
        return false;
    }
    cout << pCodec->name << endl;
    ///打开解码器
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        printf("Could not open codec.\n");
        return false;
    }

    pCodecCtx_A = pFormatCtx->streams[audioStream]->codec;
    pCodec_A = avcodec_find_decoder(pCodecCtx_A->codec_id);
    if (pCodec_A == NULL) {
        printf("pCodec_A not found.\n");
        return false;
    }
    cout << pCodec_A->name << endl;
    if(avcodec_open2(pCodecCtx_A,pCodec_A,NULL) < 0)
    {
        cout << "count not open codec." << endl;
    }
    pFrame = av_frame_alloc();
    pFrameRGB = av_frame_alloc();

    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
                                     pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
                                     AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

    int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);

    out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
    avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_RGB32,
                   pCodecCtx->width, pCodecCtx->height);

    int y_size = pCodecCtx->width * pCodecCtx->height;

    packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
    av_new_packet(packet, y_size); //分配packet的数据

    av_dump_format(pFormatCtx, 0, filename.c_str(), 0); //输出视频信息


    au_convert_ctx = swr_alloc();
    au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,
                                      av_get_default_channel_layout(pCodecCtx_A->channels),pCodecCtx->sample_fmt , pCodecCtx->sample_rate,0, NULL);
    swr_init(au_convert_ctx);

    out_buffer_a=(uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);
    out_buffer_size_A = av_samples_get_buffer_size(NULL,av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) ,pCodecCtx_A->frame_size,AV_SAMPLE_FMT_S16, 1);
    int got_picture;

    initSDL();
    cout<<__FUNCTION__<<__LINE__<<endl;
    while (running)
    {
        if (av_read_frame(pFormatCtx, packet) < 0)
        {
            break; //这里认为视频读取完了
        }
        while(!isplay){
            msleep(20);
            if(!running)
                break;
        }

        if (packet->stream_index == videoStream) {
            int ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet);

            if (ret < 0) {
                printf("decode error.\n");
                return false;
            }

            if (got_picture) {
                sws_scale(img_convert_ctx,
                          (uint8_t const * const *) pFrame->data,
                          pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                          pFrameRGB->linesize);

                //cout<<__FUNCTION__<<__LINE__<<endl;
                //SaveFrame(pFrameRGB, pCodecCtx->width,pCodecCtx->height,index++);   //保存图片
                //cout<<__FUNCTION__<<__LINE__<<endl;
                QImage tmpImg ((uchar*) out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
                QImage image = tmpImg.copy();
                emit sig_GetOneFrame(image);
                //cout<<__FUNCTION__<<__LINE__<<endl;
            }
        }
        else if(packet->stream_index == audioStream)
        {
            int ret = avcodec_decode_audio4(pCodecCtx_A,pFrame, &got_picture, packet);
            if(ret < 0)
            {
                cout <<"decode error"<< endl;
            }
            if(got_picture)
            {

                //                cout << "pFrame ->nb_samples = " << pFrame ->nb_samples << endl;
                //


                AVFrame * avFrameTmp = av_frame_alloc();
                av_frame_copy(avFrameTmp, pFrame);
                audioList.push_back(avFrameTmp);
                //cout<< "get audio data" << endl;
            }
        }
        av_free_packet(packet);
        msleep(10); //停一停  不然放的太快了
    }
    av_free(out_buffer);
    av_free(pFrameRGB);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);

    cout<<"thread is done"<<endl;
    return true;
}

void MyFFmpeg::setFilename(string filename)
{
    this->filename = filename;
    cout <<"set:"<<this->filename <<endl;
}

bool MyFFmpeg::CloseUrl()
{
    avformat_close_input(&pFormatCtx);

    return true;
}

void MyFFmpeg::avDumpFormat()
{
    av_dump_format(pFormatCtx, 0, filename.c_str(), 0); //输出视频信息
}

void MyFFmpeg::run()
{
    setFilename("C:\\Users\\Administrator\\Desktop\\test.mp4");
    OpenUrl();
}

int MyFFmpeg::avReadFrame(CAVPacket cpacket)
{
    return av_read_frame(pFormatCtx,cpacket.getAVPacket());
}

void fill_audiodata(void *udata, uint8_t *stream, int len)
{
    static int bufflen = 0;

    SDL_memset(stream, 0 , len);




    if(bufflen <= 0)  //没有剩余数据了,就要开始出队列,转化格式了。
    {
        if(audioList.size() <= 0){
            return ;
        }
        AVFrame * avframe;
        audioList.push_front(avframe);

        swr_convert(au_convert_ctx,&out_buffer_a, MAX_AUDIO_FRAME_SIZE,(const uint8_t **)avframe->data ,\
                    avframe->nb_samples);
        bufflen = out_buffer_size_A;


//        SDL_memcpy(stream,avframe->extended_data[0],len);
//        av_frame_free(&avframe);
    }
    len = (len > bufflen ? bufflen : len);
    SDL_memcpy(stream,out_buffer+(out_buffer_size_A-bufflen),len);
    bufflen -= len;


}
int MyFFmpeg::initSDL()
{
    if(SDL_Init(SDL_INIT_AUDIO|SDL_INIT_TIMER))
    {
        cout << "sdl init error!" << endl;
    }

    // int out_sample_rate = 44100;
    wanted_spec.freq = 44100;
    wanted_spec.format = AUDIO_S16SYS;
    wanted_spec.channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
    wanted_spec.silence = 0;
    wanted_spec.samples = pCodecCtx_A->frame_size;
    wanted_spec.callback = fill_audiodata;
    wanted_spec.userdata = pCodecCtx_A;

    if(SDL_OpenAudio(&wanted_spec,NULL) < 0)
    {
        cout << "can't open audio" << endl;
        return -1;
    }
    SDL_PauseAudio(0);
    return 0;
}



void MyFFmpeg::play()
{
    if(running)
    {
        if(this->isplay)
            this->isplay = false;
        else
            this->isplay = true;

    }
    else
    {
        isplay = true;
        running = true;
        this->start();
    }
}

void MyFFmpeg::stop()
{
    running = false;
}

string MyFFmpeg::getFilename() const
{
    return filename;
}

猜你喜欢

转载自blog.csdn.net/cqltbe131421/article/details/81034541
今日推荐