上一篇文章:https://blog.csdn.net/yinsui1839/article/details/127643856?spm=1001.2014.3001.5502
这两天一直阅读ffplay.c,发现AvPackct在发送给解码器之前总会调用av_packet_alloc 进行申请内存存放AvPackt然后用完后再av_packet_free()。那为什么不一次申请够,循环利用,再到程序结尾再释放,所以就有了这次改动
StreamDataPool.h 可以看我前一篇博客
//
// Created by 19321 on 2022/8/20.
//
#ifndef MY_APPLICATION_STREAMDATAPOOL_H
#define MY_APPLICATION_STREAMDATAPOOL_H
#include <iostream>
#include <list>
#include <cstring>
extern "C" {
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/fifo.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/bprint.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswscale/version.h"
#include "libswresample/swresample.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/display.h"
#include "libavutil/mathematics.h"
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libavutil/eval.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include <SDL.h>
#include <SDL_thread.h>
}
#include "StreamDataPool.h"
using namespace std;
#define MAX_CAMERA_BUFFER_SIZE 1000
#define WIGHT 640
#define HEIGHT 480
#define IMAGE_SIZE (WIGHT*HEIGHT)
#include <iostream>
#include <list>
#include "StreamDataPool.h"
#include <functional>
using namespace std;
template<class T>
class StreamDataPool {
public:
T *buf = NULL;
int mSize;
int mWriteOps = 0;
int mReadOps = 0;
bool isVaild = false;
int nb_packets;
int size;
int64_t duration;
int abort_request;
int serial;
SDL_mutex *mutex;
SDL_cond *cond;
string mName;
bool writeData(T *data) {
if (buf == NULL) return false;
if (((mWriteOps + 1) % mSize) == mReadOps) {
printf("writeOps false %d %d \n", mWriteOps, mReadOps);
return false;
}
buf[mWriteOps] = *data;
mWriteOps = (mWriteOps + 1) % mSize;
return true;
}
T *readData() {
if (buf == NULL) return NULL;
if (mReadOps == mWriteOps) {
printf("readData false %d %d \n", mWriteOps, mReadOps);
return NULL;
}
int readOps = mReadOps;
mReadOps = (mReadOps + 1) % mSize;
return &buf[readOps];
}
list<void *> ReadBufferList(bool isOnlyRead) {
list<void *> dataList;
if (buf == NULL) return dataList;
int readOps = mReadOps;
while (readOps != mWriteOps) {
dataList.push_back(&buf[readOps]);
readOps = (readOps + 1) % mSize;
}
if (!isOnlyRead) {
mReadOps = readOps;
}
return dataList;
}
void pop() {
if (mReadOps == mWriteOps) return;
mReadOps = (mReadOps + 1) % mSize;
}
void setSize(int size) {
mSize = size;
mWriteOps = 0;
mReadOps = 0;
buf = new T[size];
}
void setSize(int size, string name) {
mSize = size;
mWriteOps = 0;
mReadOps = 0;
serial = 0;
buf = new T[size];
mName = name;
}
void destroy() {
isVaild = false;
if (buf != NULL) {
delete buf;
buf = NULL;
}
}
bool isFull(){
if(mWriteOps - mReadOps == mSize) return true;
}
bool isEnty(){
if(mReadOps - mWriteOps) return true;
return false;
}
void clean(){
mWriteOps = 0;
mReadOps = 0;
}
};
class PktNode{
public:
int index = 0;
int64_t pts = 0;
int type = 0;
PktNode(){
};
PktNode(int Index ,int64_t Pts,int Type ){
this->index=Index;
this->pts=Pts;
this->type=Type;
};
PktNode &operator=(PktNode &data) {
this->index=data.index;
this->pts=data.pts;
this->type=data.type;
return *this;
}
};
class PktPool {
public:
AVPacket *pkt = NULL;
int serial=0;
int index = 0;
static int curIndex;
PktPool() {
pkt = av_packet_alloc();
};
~PktPool(){
av_packet_free(&pkt);
}
PktPool &operator=(AVPacket *data) {
if(pkt != NULL){
av_packet_move_ref(this->pkt, data);
}
return *this;
}
PktPool &operator=(PktPool &data) {
av_packet_move_ref(this->pkt, data.pkt);
return *this;
}
void free(){
av_packet_unref(this->pkt);
}
static PktPool *PktPoolPtr;
static PktPool *GetPktPool() {
curIndex = (curIndex + 1) % MAX_CAMERA_BUFFER_SIZE;
PktPoolPtr[curIndex].index = curIndex;
return &PktPoolPtr[curIndex];
}
};
PktPool* PktPool::PktPoolPtr = new PktPool[MAX_CAMERA_BUFFER_SIZE];
int PktPool::curIndex = 0;
#endif //MY_APPLICATION_STREAMDATAPOOL_H
ffplay.cpp
/*
*主要修改了PacketQueue *q 改为 StreamDataPool<PktNode> *q
*优化代码每一次packet_queue_put_private都会调用av_fifo_write,解码的时候还要调用*av_fifo_read获取,减少FFmepeg API使用
*/
static int packet_queue_put_private(StreamDataPool<PktNode> *q, PktPool *pktPool)
{
bool ret;
if (q->abort_request)
return -1;
PktNode pktNode(pktPool->index, pktPool->pkt->pts, pktPool->pkt->stream_index);
ret = q->writeData(&pktNode);
if (ret == false)
return -1;
q->nb_packets++;
q->size += pktPool->pkt->size;
q->duration += pktPool->pkt->duration;
/* XXX: should duplicate packet data in DV case */
SDL_CondSignal(q->cond);
return 0;
}
static int packet_queue_put(StreamDataPool<PktNode> *q, AVPacket *pkt)
{
int ret;
PktPool *pktPool = PktPool::GetPktPool();//在内存池里获取到对应的pktPool容器
if (pktPool == NULL)
{
av_packet_unref(pkt);
return -1;
}
SDL_LockMutex(q->mutex);
*pktPool = pkt; //赋值
pktPool->serial = q->serial;
packet_queue_put_private(q,pktPool);
SDL_UnlockMutex(q->mutex);
return ret;
}
/* return < 0 if aborted, 0 if no packet and > 0 if packet. g++ fftools/ffplay.cpp -I /usr/local/include -I /usr/include/SDL2/ -L /usr/local/lib -lavformat -lavcodec -lavutil -lswscale -lSDL2 -lavformat -lavcodec -lavdevice -lavutil -lz -lm -lswresample -lpostproc*/
static int packet_queue_get(StreamDataPool<PktNode> *q, AVPacket *pkt, int block, int *serial)
{
int ret;
SDL_LockMutex(q->mutex);
for (;;)
{
if (q->abort_request)
{
ret = -1;
break;
}
PktNode *pktNode = q->readData();//从数据队列获取对应的节点
PktPool *pktPool = NULL;
if (pktNode != NULL)
{
pktPool = &PktPool::PktPoolPtr[pktNode->index];//获取对应的数据内存段
}
if (pktPool != NULL)
{
q->nb_packets--;
q->size -= pktPool->pkt->size;
q->duration -= pktPool->pkt->duration;
av_packet_move_ref(pkt, pktPool->pkt);
if (serial)
*serial = pktPool->serial;
ret = 1;
break;
}
else if (!block)
{
ret = 0;
break;
}
else
{
SDL_CondWait(q->cond, q->mutex);
}
}
// printf("ret = %d",ret);
SDL_UnlockMutex(q->mutex);
return ret;
}
原版:
/*
*原版
*优化代码每一次packet_queue_put_private都会调用av_fifo_write,解码的时候还要调用*av_fifo_read获取,减少FFmepeg API使用
*/
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
MyAVPacketList pkt1;
int ret;
if (q->abort_request)
return -1;
pkt1.pkt = pkt;
pkt1.serial = q->serial;
ret = av_fifo_write(q->pkt_list, &pkt1, 1);
if (ret < 0)
return ret;
q->nb_packets++;
q->size += pkt1.pkt->size + sizeof(pkt1);
q->duration += pkt1.pkt->duration;
/* XXX: should duplicate packet data in DV case */
SDL_CondSignal( q->cond);
return 0;
}
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
{
AVPacket *pkt1;
int ret;
pkt1 = av_packet_alloc();
if (!pkt1) {
av_packet_unref(pkt);
return -1;
}
av_packet_move_ref(pkt1, pkt);
SDL_LockMutex(q->mutex);
ret = packet_queue_put_private(q, pkt1);
SDL_UnlockMutex(q->mutex);
if (ret < 0)
av_packet_free(&pkt1);
return ret;
}
static int packet_queue_put_nullpacket(PacketQueue *q, AVPacket *pkt, int stream_index)
{
pkt->stream_index = stream_index;
return packet_queue_put(q, pkt);
}
/* packet queue handling */
static int packet_queue_init(PacketQueue *q)
{
memset(q, 0, sizeof(PacketQueue));
q->pkt_list = av_fifo_alloc2(1, sizeof(MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW);
if (!q->pkt_list)
return AVERROR(ENOMEM);
q->mutex = SDL_CreateMutex();
if (!q->mutex) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
q->cond = SDL_CreateCond();
if (!q->cond) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
q->abort_request = 1;
return 0;
}
ffplay.cpp 主要替换PacketQueue *q 为StreamDataPool<PktNode> *q,剔除av_fifo_write av_fifo_read 改为从数据池里获取
编译:g++ ffplay.cpp StreamDataPool.cpp StreamDataPool.h -I /usr/local/include -I /usr/include/SDL2/ -L /usr/local/lib -lavformat -lavcodec -lavutil -lswscale -lSDL2 -lavformat -lavcodec -lavdevice -lavutil -lz -lm -lswresample -lpostproc
编译后可正常播放视频https://download.csdn.net/download/yinsui1839/86876644