首先创建video的c++类
video.h
在本类中声明一个线程thread_play 利用此线程获取队列里面的数据
声明一个void play(); 来启动线程
#ifndef MYMUSIC_WLVIDEO_H
#define MYMUSIC_WLVIDEO_H
#include "WlQueue.h"
#include "WlCallJava.h"
extern "C"
{
#include <libavcodec/avcodec.h>
};
class WlVideo {
public:
//视频流的索引
int streamIndex = -1;
//解码器上下文
AVCodecContext *avCodecContext = NULL;
//解码器属性
AVCodecParameters *codecpar = NULL;
//队列存储avPacket
WlQueue *queue = NULL;
WlPlaystatus *playstatus = NULL;
//回调java方法的类
WlCallJava *wlCallJava = NULL;
AVRational time_base;
pthread_t thread_play;
public:
WlVideo(WlPlaystatus *playstatus, WlCallJava *wlCallJava);
~WlVideo();
void play();
};
#endif //MYMUSIC_WLVIDEO_H
video.cpp
#include "WlVideo.h"
WlVideo::WlVideo(WlPlaystatus *playstatus, WlCallJava *wlCallJava) {
this->playstatus = playstatus;
this->wlCallJava = wlCallJava;
//队列初始化
queue = new WlQueue(playstatus);
}
//回调函数
void * playVideo(void *data)
{
WlVideo *video = static_cast<WlVideo *>(data);
while(video->playstatus != NULL && !video->playstatus->exit)
{
AVPacket *avPacket = av_packet_alloc();
if(video->queue->getAvpacket(avPacket) == 0)
{
//解码渲染
LOGE("线程中获取视频AVpacket");
}
av_packet_free(&avPacket);
av_free(avPacket);
avPacket = NULL;
}
//不要忘记退出线程
pthread_exit(&video->thread_play);
}
//播放函数中创建线程 编写回调函数
void WlVideo::play() {
pthread_create(&thread_play, NULL, playVideo, this);
}
在 FFmpeg.h 里面声明video对象(不要忘记导包)
WlVideo *video = NULL;
在 FFmpeg.h 声明一个公共获取解码器上下文的方法
int getCodecContext(AVCodecParameters *codecpar, AVCodecContext **avCodecContext);
在 FFmpeg.cpp 中写方法的实现
int WlFFmpeg::getCodecContext(AVCodecParameters *codecpar, AVCodecContext **avCodecContext) {
AVCodec *dec = avcodec_find_decoder(codecpar->codec_id);
if(!dec)
{
if(LOG_DEBUG)
{
LOGE("can not find decoder");
}
callJava->onCallError(CHILD_THREAD, 1003, "can not find decoder");
exit = true;
pthread_mutex_unlock(&init_mutex);
return -1;
}
//初始化avCodecContext
*avCodecContext = avcodec_alloc_context3(dec);
if(!audio->avCodecContext)
{
if(LOG_DEBUG)
{
LOGE("can not alloc new decodecctx");
}
callJava->onCallError(CHILD_THREAD, 1004, "can not alloc new decodecctx");
exit = true;
pthread_mutex_unlock(&init_mutex);
return -1;
}
if(avcodec_parameters_to_context(*avCodecContext, codecpar) < 0)
{
if(LOG_DEBUG)
{
LOGE("can not fill decodecctx");
}
callJava->onCallError(CHILD_THREAD, 1005, "ccan not fill decodecctx");
exit = true;
pthread_mutex_unlock(&init_mutex);
return -1;
}
if(avcodec_open2(*avCodecContext, dec, 0) != 0)
{
if(LOG_DEBUG)
{
LOGE("cant not open audio strames");
}
callJava->onCallError(CHILD_THREAD, 1006, "cant not open audio strames");
exit = true;
pthread_mutex_unlock(&init_mutex);
return -1;
}
return 0;
}
在 FFmpeg.cpp void WlFFmpeg::decodeFFmpegThread() 方法 for(int i = 0; i < pFormatCtx->nb_streams; i++) 下获取视频流
else if(pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
if(video == NULL)
{
video = new WlVideo(playstatus, callJava);
video->streamIndex = i;
video->codecpar = pFormatCtx->streams[i]->codecpar;
video->time_base = pFormatCtx->streams[i]->time_base;
}
}
/*if(audio != NULL)
{
getCodecContext(audio->codecpar, &audio->avCodecContext);
}*/
//打开视频解码器
if(video != NULL)
{
getCodecContext(video->codecpar, &video->avCodecContext);
}
在 FFmpeg.cpp void FFmpeg::start() 方法中 av_read_frame函数下 在这个过程中将avPacket放入队列中
else if(avPacket->stream_index == video->streamIndex)
{
video->queue->putAvpacket(avPacket);
}
在 FFmpeg.cpp void FFmpeg::start() 方法中 直接调用
video->play();