Слияние кода завершено, страница обновится автоматически
#include "zffmpeg.h"
#include "zffaudio.h"
#include "zffvideo.h"
QAtomicPointer<ZFFmpeg> ZFFmpeg::_instance = 0;
QMutex ZFFmpeg::_mutex;
ZFFmpeg::ZFFmpeg()
{
avcodec_register_all();
av_register_all();
}
ZFFmpeg * ZFFmpeg::getInstance()
{
// 使用双重检测。
/*! testAndSetOrders操作保证在原子操作前和后的的内存访问
* 不会被重新排序。
*/
if (_instance.testAndSetOrdered(0, 0)) // 第一次检测
{
QMutexLocker locker(&_mutex); // 加互斥锁。
_instance.testAndSetOrdered(0, new ZFFmpeg); // 第二次检测。
}
return _instance;
}
int ZFFmpeg::Load(QString fileName) {
// TODO: 路径格式是否正确
if (fileName.isEmpty()) {
return false;
}
QMutexLocker locker(&_mutex); // 加互斥锁
pFormatCtx = avformat_alloc_context();
int ret =
avformat_open_input(&pFormatCtx, fileName.toLocal8Bit().data(), 0, 0); //
//
// 打开解封装器
if (ret != 0)
{
qDebug("Couldn't open input stream.");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
qDebug("Couldn't find stream information.");
return -1;
}
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
AVCodecContext *enc = pFormatCtx->streams[i]->codec; // 解码上下文
if (enc->codec_type == AVMEDIA_TYPE_VIDEO) // 判断是否为视频
{
videoStream = i;
// AVRational avr = pFormatCtx->streams[i]->avg_frame_rate;
AVCodec *codec = avcodec_find_decoder(enc->codec_id); // 查找解码器
if (!codec) // 未找到解码器
{
printf("video code not find\n");
return false;
}
int err = avcodec_open2(enc, codec, NULL); // 打开解码器
if (err != 0) // 未打开解码器
{
return false;
}
videoWidth = enc->width;
videoHeight = enc->height;
qDebug("open codec success, width=%d,height=%d!\n",
enc->width,
enc->height);
} else if (enc->codec_type == AVMEDIA_TYPE_AUDIO) // 若未音频流
{
audioStream = i; // 音频流
AVCodec *codec = avcodec_find_decoder(enc->codec_id); // 查找解码器
if (avcodec_open2(enc, codec, NULL) < 0)
{
return 0;
}
// qDebug("%d %d",codec,pFormatCtx->streams[audioStream]->codec);
_audioInfo.sample_rate = enc->sample_rate; // 样本率
_audioInfo.channel = enc->channels; // 通道数
switch (enc->sample_fmt) // 样本大小
{
case AV_SAMPLE_FMT_S16: // signed 16 bits
_audioInfo.sample_fmt = 16;
break;
case AV_SAMPLE_FMT_S32: // signed 32 bits
_audioInfo.sample_fmt = 32;
default:
_audioInfo.sample_fmt = enc->sample_fmt;
break;
}
// qDebug("%d",enc->sample_fmt);
qDebug("audio sample rate:%d sample size:%d chanle:%d\n",
_audioInfo.sample_rate,
_audioInfo.sample_fmt,
_audioInfo.channel);
}
}
_totalTimeSec = (float)pFormatCtx->duration / (AV_TIME_BASE); // 获取视频的总时间
qDebug("totalTimeSec:%f", this->_totalTimeSec);
// 至此为打开解码器过程
// FFAudio::getInstance()->Start();
// TODO:缓存数据
aCtx = swr_alloc();
AVCodecContext *ctx = pFormatCtx->streams[audioStream]->codec;
swr_alloc_set_opts(aCtx,
ctx->channel_layout, // out
AV_SAMPLE_FMT_S16, // out
44100, // out
ctx->channel_layout, // in
ctx->sample_fmt, // in
ctx->sample_rate, // in
0, 0);
swr_init(aCtx);
qDebug("channel_layout:%d", ctx->channels);
return true;
}
AVPacket ZFFmpeg::Read() {
AVPacket pkt;
memset(&pkt, 0, sizeof(AVPacket));
QMutexLocker locker(&_mutex); // 加互斥锁
int err = av_read_frame(pFormatCtx, &pkt); // 读取帧
if (err != 0) // 读取失败
{
pkt.size = -1;
}
// qDebug("read:%f",GetPts(&pkt));
return pkt;
}
AVFrame * ZFFmpeg::Decode(AVPacket *pkt) {
QMutexLocker locker(&_mutex); // 加互斥锁
if (!pFormatCtx) // 若未打开视频
{
return NULL;
}
AVFrame *frameTemp = av_frame_alloc();
int ret = avcodec_send_packet(pFormatCtx->streams[pkt->stream_index]->codec,
pkt);
// av_packet_unref(pkt);//释放pkt包
if (ret != 0)
{
// mutex.unlock();
return NULL;
}
ret = avcodec_receive_frame(pFormatCtx->streams[pkt->stream_index]->codec,
frameTemp); // 解码pkt后存入frame中
if (ret != 0)
{
return NULL;
}
return frameTemp;
}
int ZFFmpeg::Seek(float pos)
{
QMutexLocker locker(&_mutex); // 加互斥锁
if (!pFormatCtx) // 未打开视频
{
return -1;
}
int re = av_seek_frame(pFormatCtx,
-1,
(int64_t)pos * AV_TIME_BASE,
AVSEEK_FLAG_ANY); // 将视频移至到当前点击滑动条位置
if (re > 0) {
qDebug("seek error");
return -1;
}
if (re > 0) {
qDebug("seek error");
return -1;
}
return 0;
}
void ZFFmpeg::start(Priority pro) {
cacheData = true;
_isStop = false;
QThread::start(pro);
qDebug("ZFFmpeg start");
}
void ZFFmpeg::run() {
while (cacheData) {
// qDebug("run:%d %d",videoList.list.size(),audioList.list.size());
if ((videoList.list.size() > LIST_CACHE_LENGTH) &&
(audioList.list.size() > LIST_CACHE_LENGTH)) {
msleep(20);
continue;
}
{
AVPacket pkt = Read(); // 读取视频帧
if (pkt.size < 0) // 未打开视频
{
qDebug("open failed");
cacheData = false;
break;
}
if (pkt.stream_index == audioStream) /* 音频 */
{
QMutexLocker locker(&audioList._mutex);
audioList.list.append(pkt);
continue;
} else if (pkt.stream_index == videoStream) /* 视频 */
{
QMutexLocker locker(&videoList._mutex);
videoList.list.append(pkt);
continue;
}
}
}
_isStop = true;
}
float ZFFmpeg::GetPts(AVPacket *pkt) {
return pkt->pts * av_q2d(pFormatCtx->streams[pkt->stream_index]->time_base);
}
int ZFFmpeg::play() {
start();
ZFFaudio::getInstance()->start();
ZFFvideo::getInstance()->start();
qDebug("start");
return 0;
}
int ZFFmpeg::pause() {
ZFFaudio::getInstance()->terminate();
ZFFvideo::getInstance()->terminate();
return 0;
}
int ZFFmpeg::stop() {
cacheData = false;
msleep(20);
ZFFaudio::getInstance()->stop();
ZFFvideo::getInstance()->stop();
msleep(20);
clearList();
Seek(0);
return 0;
}
int ZFFmpeg::GetTotalTimeMsec() {
return (int)(_totalTimeSec * 1000);
}
int ZFFmpeg::GetCurTimeMsec() {
return (int)(ZFFaudio::getInstance()->GetCurTimeSec() * 1000);
}
int ZFFmpeg::seekPosByMs(float pos) {
cacheData = false;
msleep(20);
ZFFaudio::getInstance()->stop();
ZFFvideo::getInstance()->stop();
msleep(20);
clearList();
Seek(pos / 1000.0);
// play();
return 0;
}
void ZFFmpeg::clearList() {
while (audioList.list.size() > 0) {
AVPacket pkt = audioList.list.takeFirst();
av_packet_unref(&pkt);
}
while (videoList.list.size() > 0) {
AVPacket pkt = videoList.list.takeFirst();
av_packet_unref(&pkt);
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )