-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
444 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
#include "framequeue.h" | ||
#include <QMutexLocker> | ||
|
||
FrameQueue::FrameQueue() | ||
{ | ||
} | ||
|
||
//************************************ | ||
// Method: enQueue | ||
// FullName: FrameQueue::enQueue | ||
// Access: public | ||
// Returns: bool | ||
// Qualifier: 帧队列入队 | ||
// Parameter: const AVFrame * frame | ||
//************************************ | ||
bool FrameQueue::enQueue(const AVFrame* frame) | ||
{ | ||
AVFrame* p = av_frame_alloc(); | ||
|
||
int ret = av_frame_ref(p, frame); | ||
if (ret < 0) | ||
return false; | ||
p->opaque = (void *)new double(*(double*)p->opaque); //上一个指向的是一个局部的变量,这里重新分配pts空间 | ||
QMutexLocker locker(&mutex); | ||
queue.push(p); | ||
cond.wakeOne(); | ||
return true; | ||
} | ||
|
||
//************************************ | ||
// Method: deQueue | ||
// FullName: FrameQueue::deQueue | ||
// Access: public | ||
// Returns: AVFrame * | ||
// Qualifier:帧队列 | ||
//************************************ | ||
AVFrame * FrameQueue::deQueue() | ||
{ | ||
bool ret = true; | ||
AVFrame *tmp; | ||
QMutexLocker locker(&mutex); | ||
while (true) | ||
{ | ||
if (!queue.empty()) | ||
{ | ||
tmp = queue.front(); | ||
queue.pop(); | ||
ret = true; | ||
break; | ||
} | ||
else | ||
{ | ||
cond.wait(&mutex); | ||
} | ||
} | ||
|
||
return tmp; | ||
} | ||
|
||
//************************************ | ||
// Method: getQueueSize | ||
// FullName: FrameQueue::getQueueSize | ||
// Access: public | ||
// Returns: int | ||
// Qualifier:获取队列大小 | ||
//************************************ | ||
int FrameQueue::getQueueSize() | ||
{ | ||
return queue.size(); | ||
} | ||
|
||
//************************************ | ||
// Method: queueFlush | ||
// FullName: FrameQueue::queueFlush | ||
// Access: public | ||
// Returns: void | ||
// Qualifier:清空帧队列 | ||
//************************************ | ||
void FrameQueue::queueFlush() { | ||
while (!queue.empty()) | ||
{ | ||
AVFrame *frame = deQueue(); | ||
av_frame_unref(frame); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#ifndef FRAMEQUEUE_H | ||
#define FRAMEQUEUE_H | ||
|
||
#include <queue> | ||
#include <QMutex> | ||
#include <QWaitCondition> | ||
#include "avcommon.h" | ||
|
||
class FrameQueue | ||
{ | ||
public: | ||
static const int capacity = 30; | ||
FrameQueue(); | ||
bool enQueue(const AVFrame* frame); | ||
AVFrame * deQueue(); | ||
int getQueueSize(); | ||
void queueFlush(); | ||
private: | ||
std::queue<AVFrame*> queue; | ||
QMutex mutex; | ||
QWaitCondition cond; | ||
}; | ||
|
||
#endif // FRAMEQUEUE_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
#include "media.h" | ||
#include "audio.h" | ||
#include "video.h" | ||
#include "logging/log.h" | ||
|
||
//#include "ReadPacketsThread.h" | ||
//#include "DisplayMediaTimer.h" | ||
extern "C" { | ||
#include <libavutil/time.h> | ||
} | ||
|
||
extern std::shared_ptr<LogHandler> logHandler; | ||
static CommonLog commonLogger(logHandler,"media"); | ||
#define MEDIA_LOG(level) COMMON_LOG(commonLogger, level) | ||
|
||
const static long long MAX_AUDIOQ_SIZE = (5 * 16 * 1024);//最大音频包大小(队列中所有加起来的大小) | ||
const static long long MAX_VIDEOQ_SIZE = (5 * 256 * 1024);//最大视频包大小(队列中所有视频包加起来的大小) | ||
|
||
//************************************ | ||
// Method: r2d | ||
// FullName: r2d | ||
// Access: public static | ||
// Returns: double | ||
// Qualifier: 时间基准计算 | ||
// Parameter: AVRational r | ||
//************************************ | ||
static double r2d(AVRational r) | ||
{ | ||
return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den; | ||
} | ||
|
||
Media::Media() | ||
{ | ||
av_register_all();//注册ffmpeg所有组件 | ||
avformat_network_init();//注册网络组件 | ||
pFormatCtx = nullptr; | ||
audio = new Audio; | ||
video = new Video; | ||
} | ||
|
||
//************************************ | ||
// Method: config | ||
// FullName: Media::config | ||
// Access: public | ||
// Returns: Media::Media * | ||
// Qualifier:配置视频 | ||
//************************************ | ||
Media * Media::config() { | ||
close(); | ||
QMutexLocker locker(&mutex); | ||
char errorbuf[1024] = { 0 }; | ||
int ret = avformat_open_input(&pFormatCtx, filename, 0, 0); | ||
if (ret < 0) { | ||
av_strerror(ret, errorbuf, sizeof(errorbuf)); | ||
MEDIA_LOG(ERR) << "open " << filename << "failed, error:" << errorbuf << std::endl; | ||
return nullptr; | ||
} | ||
|
||
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0) { | ||
MEDIA_LOG(ERR) << "avformat_find_stream_info" << errorbuf << std::endl; | ||
return nullptr; | ||
} | ||
//av_dump_format(pFormatCtx, 0, filename, 0); | ||
totalMs = ((pFormatCtx->duration / AV_TIME_BASE) * 1000);//计算视频总时长 | ||
video->setStreamIndex(-1);//设置音视频流下标为-1,因为需要多次打开不同音视频 | ||
audio->setStreamIndex(-1); | ||
for (uint32_t i = 0; i < pFormatCtx->nb_streams; i++) | ||
{ | ||
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio->getStreamIndex() < 0) | ||
audio->setStreamIndex(i); | ||
|
||
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video->getStreamIndex() < 0) | ||
video->setStreamIndex(i); | ||
} | ||
|
||
if (audio->getStreamIndex() < 0 || video->getStreamIndex() < 0) { | ||
return nullptr; | ||
} | ||
|
||
// 设置音频状态 | ||
AVCodec *pCodec = avcodec_find_decoder(pFormatCtx->streams[audio->getStreamIndex()]->codec->codec_id); | ||
if (!pCodec) { | ||
return nullptr; | ||
} | ||
|
||
audio->setStream(pFormatCtx->streams[audio->getStreamIndex()]); | ||
|
||
audio->setAVCodecContext(avcodec_alloc_context3(pCodec)); | ||
|
||
if (avcodec_copy_context(audio->getAVCodecContext(), pFormatCtx->streams[audio->getStreamIndex()]->codec) != 0) { | ||
return nullptr; | ||
} | ||
|
||
avcodec_open2(audio->getAVCodecContext(), pCodec, nullptr); | ||
|
||
// 设置视频状态 | ||
AVCodec *pVCodec = avcodec_find_decoder(pFormatCtx->streams[video->getStreamIndex()]->codec->codec_id); | ||
if (!pVCodec) { | ||
return nullptr; | ||
} | ||
|
||
video->setVideoStream(pFormatCtx->streams[video->getStreamIndex()]); | ||
|
||
video->setAVCodecCotext(avcodec_alloc_context3(pVCodec)); | ||
if (avcodec_copy_context(video->getAVCodecCotext(), pFormatCtx->streams[video->getStreamIndex()]->codec) != 0) { | ||
return nullptr; | ||
} | ||
|
||
avcodec_open2(video->getAVCodecCotext(), pVCodec, nullptr); | ||
|
||
video->setFrameTimer(static_cast<double>(av_gettime()) / 1000000.0);//设置初始视频帧时间用于音视同步 | ||
video->setFrameLastDelay(40e-3) ;//计算时间,TODO*/ | ||
audio->audioPlay(); | ||
//ReadPacketsThread::getInstance()->setPlaying(true); | ||
//DisplayMediaTimer::getInstance()->setPlay(true); | ||
return this; | ||
} | ||
|
||
//************************************ | ||
// Method: setMediaFile | ||
// FullName: Media::setMediaFile | ||
// Access: public | ||
// Returns: Media::Media * | ||
// Qualifier: 设置视频文件 | ||
// Parameter: const char * filename 视频文件名字 | ||
//************************************ | ||
Media * Media::setMediaFile(const char * filename) | ||
{ | ||
this->filename = filename; | ||
return this; | ||
} | ||
|
||
//************************************ | ||
// Method: checkMediaSizeValid | ||
// FullName: Media::checkMediaSizeValid | ||
// Access: public | ||
// Returns: bool | ||
// Qualifier: 检查视频大小是否合法 | ||
//************************************ | ||
bool Media::checkMediaSizeValid() | ||
{ | ||
if (this->audio == nullptr || this->video == nullptr) { | ||
return true; | ||
} | ||
Uint32 audioSize = this->audio->getAudioQueueSize(); | ||
Uint32 videoSize = this->video->getVideoQueueSize(); | ||
return (audioSize> MAX_AUDIOQ_SIZE || videoSize> MAX_VIDEOQ_SIZE); | ||
} | ||
|
||
//************************************ | ||
// Method: getVideoStreamIndex | ||
// FullName: Media::getVideoStreamIndex | ||
// Access: public | ||
// Returns: int | ||
// Qualifier: 获取视频流信息 | ||
//************************************ | ||
int Media::getVideoStreamIndex() | ||
{ | ||
return video->getStreamIndex(); | ||
} | ||
|
||
//************************************ | ||
// Method: getAudioStreamIndex | ||
// FullName: Media::getAudioStreamIndex | ||
// Access: public | ||
// Returns: int | ||
// Qualifier:获取音频流下标 | ||
//************************************ | ||
int Media::getAudioStreamIndex() | ||
{ | ||
return audio->getStreamIndex(); | ||
} | ||
|
||
//************************************ | ||
// Method: enqueueVideoPacket | ||
// FullName: Media::enqueueVideoPacket | ||
// Access: public | ||
// Returns: void | ||
// Qualifier:视频包入队 | ||
// Parameter: const AVPacket & packet | ||
//************************************ | ||
void Media::enqueueVideoPacket(const AVPacket &packet) | ||
{ | ||
video->enqueuePacket(packet); | ||
} | ||
|
||
//************************************ | ||
// Method: enqueueAudioPacket | ||
// FullName: Media::enqueueAudioPacket | ||
// Access: public | ||
// Returns: void | ||
// Qualifier:音频包入队 | ||
// Parameter: const AVPacket & packet | ||
//************************************ | ||
void Media::enqueueAudioPacket(const AVPacket &packet) | ||
{ | ||
audio->enqueuePacket(packet); | ||
} | ||
|
||
//************************************ | ||
// Method: startAudioPlay | ||
// FullName: Media::startAudioPlay | ||
// Access: public | ||
// Returns: void | ||
// Qualifier: 音频开始播放 | ||
//************************************ | ||
void Media::startAudioPlay() | ||
{ | ||
audio->audioPlay(); | ||
} | ||
|
||
//************************************ | ||
// Method: getAVFormatContext | ||
// FullName: Media::getAVFormatContext | ||
// Access: public | ||
// Returns: AVFormatContext * | ||
// Qualifier:获取音视频文件格式上下文 | ||
//************************************ | ||
AVFormatContext * Media::getAVFormatContext() | ||
{ | ||
QMutexLocker locker(&mutex); | ||
AVFormatContext * p = pFormatCtx; | ||
return p; | ||
} | ||
|
||
//************************************ | ||
// Method: close | ||
// FullName: Media::close | ||
// Access: public | ||
// Returns: void | ||
// Qualifier:关闭,回收资源 | ||
//************************************ | ||
void Media::close() | ||
{ | ||
QMutexLocker locker(&mutex); | ||
audio->audioClose(); | ||
audio->clearPacket(); | ||
video->clearFrames(); | ||
video->clearPackets(); | ||
|
||
if (pFormatCtx) { | ||
avformat_close_input(&pFormatCtx); | ||
pFormatCtx = nullptr; | ||
} | ||
|
||
|
||
if (video->swsContext) | ||
{ | ||
sws_freeContext(video->swsContext); | ||
video->swsContext = NULL; | ||
} | ||
//ReadPacketsThread::getInstance()->setPlaying(false); | ||
//DisplayMediaTimer::getInstance()->setPlay(false); | ||
|
||
} | ||
|
||
Media::~Media() | ||
{ | ||
QMutexLocker locker(&mutex); | ||
if (audio != nullptr){ | ||
delete audio; | ||
audio = nullptr; | ||
} | ||
|
||
if (video != nullptr) { | ||
delete video; | ||
//video = nullptr; | ||
} | ||
|
||
} |
Oops, something went wrong.