From 93f44a10e2e8942e57e62bb210a2ca7d206a51b7 Mon Sep 17 00:00:00 2001
From: zhangmeng <775834166@qq.com>
Date: 星期二, 24 九月 2019 11:26:44 +0800
Subject: [PATCH] add rec audio;
---
csrc/buz/recorder.hpp | 12
csrc/buz/recorder.cpp | 54 +--
csrc/ffmpeg/format/FormatIn.hpp | 19 -
csrc/ffmpeg/format/FormatIn.cpp | 98 +-----
csrc/ffmpeg/format/FormatOut.hpp | 25 -
/dev/null | 22 -
csrc/wrapper.cpp | 68 ++--
csrc/worker/rec.cpp | 18
csrc/worker/stream.cpp | 42 +-
csrc/worker/decoder.cpp | 140 ++++++++--
csrc/wrapper.hpp | 8
csrc/ffmpeg/format/FormatOut.cpp | 176 ++++---------
csrc/worker/rec.hpp | 5
csrc/worker/stream.hpp | 7
csrc/worker/decoder.hpp | 17 +
csrc/common.hpp | 16 +
16 files changed, 326 insertions(+), 401 deletions(-)
diff --git a/csrc/all.hpp b/csrc/all.hpp
deleted file mode 100644
index 5f709fe..0000000
--- a/csrc/all.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _cffmpeg_wrapper_all_hpp_
-#define _cffmpeg_wrapper_all_hpp_
-
-
-#include "ffmpeg/bridge/cvbridge.cpp"
-#include "ffmpeg/configure/conf.cpp"
-#include "ffmpeg/data/CodedData.cpp"
-#include "ffmpeg/data/FrameData.cpp"
-#include "ffmpeg/data/PicData.cpp"
-#include "ffmpeg/filter/FilterVideo.cpp"
-#include "ffmpeg/format/FormatIn.cpp"
-#include "ffmpeg/format/FormatOut.cpp"
-#include "ffmpeg/log/log.cpp"
-#include "ffmpeg/property/VideoProp.cpp"
-#include "ffmpeg/swscale/swscale_wrapper.cpp"
-#include "common/filesystem.cpp"
-#include "common/gpu/info.cpp"
-#include "thirdparty/whereami/whereami.c"
-#include "wrapper.cpp"
-#include "buz/recorder.cpp"
-
-#endif
\ No newline at end of file
diff --git a/csrc/buz/recorder.cpp b/csrc/buz/recorder.cpp
index 86afe89..2726861 100644
--- a/csrc/buz/recorder.cpp
+++ b/csrc/buz/recorder.cpp
@@ -71,17 +71,10 @@
}
out_ = new FormatOut(in_->getFPS(), "mp4");
- AVStream *vs = in_->getStream(0);
- AVStream *as = in_->getStream(1);
- if (!vs) return -1;
- if (audio && !as) logIt("there is no audio");
- std::vector<AVStream*> in;
- in.push_back(vs);
- if (audio && as) in.push_back(as);
file_path_ = dir_ + "/" + sole::uuid4().base62() + ".mp4";
- auto ret = out_->JustWriter(in, file_path_.c_str());
+ auto ret = out_->JustWriter(in_->getFromatContext(), file_path_.c_str());
if (ret){
return 0;
}
@@ -99,17 +92,23 @@
return 1;
}
- int64_t cur = cur_frame++;
AVPacket &op = pkt.data->getAVPacket();
AVPacket np(op);
av_copy_packet(&np, &op);
- auto ret = out_->writeFrame(np, cur);
- av_packet_unref(&np);
- if (!ret) return -1;
- if(pkt.id == id_frame_){
- id_frame_in_file_ = cur_frame-1;
+ int64_t cur = cur_frame;
+ if (in_->isVideoPkt(&np)){
+
+ if(pkt.id == id_frame_){
+ id_frame_in_file_ = cur_frame;
+ }
+ cur_frame++;
}
+
+ auto ret = out_->writeFrame(&np, cur);
+ av_packet_unref(&np);
+
+ if (!ret) return -1;
// logIt("WRITE FRAME ID: %d, RECORD ID: %d", pkt.id, id_frame_);
return 0;
@@ -232,15 +231,8 @@
if(id_frame_ == -1){
//wait I
- if (!audio_ && in_->isAudioPkt(pkt.data->getAVPacket())){
- return 0;
- }
-
- if (list_pkt_.empty()) {
- AVPacket &avpkt = pkt.data->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
- return -1;
- }
+ if (!audio_ && in_->isAudioPkt(&pkt.data->getAVPacket())){
+ return 0;
}
maybe_dump_gop();
@@ -263,15 +255,8 @@
std::lock_guard<std::mutex> locker(mutex_pkt_);
bool i = false;
for (auto &p : lst){
- if (!i){
- if (!audio_ && in_->isAudioPkt(p.data->getAVPacket())){
- continue;
- }
- AVPacket &avpkt = p.data->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
- continue;
- }
- i = true;
+ if (!audio_ && in_->isAudioPkt(&p.data->getAVPacket())){
+ continue;
}
list_pkt_.push_back(p);
@@ -288,9 +273,8 @@
while (list_pkt_.size() > minduration) {
list_pkt_.pop_front();
while(!list_pkt_.empty()){
- auto &cache = list_pkt_.front();
- AVPacket &avpkt = cache.data->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
+ auto &i = list_pkt_.front();
+ if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
list_pkt_.pop_front();
}else{
break;
diff --git a/csrc/buz/recorder.hpp b/csrc/buz/recorder.hpp
index f044907..4b22af8 100644
--- a/csrc/buz/recorder.hpp
+++ b/csrc/buz/recorder.hpp
@@ -13,21 +13,17 @@
#include "../common/callback.hpp"
+#include "../common.hpp"
+
+struct AVPacket;
+
namespace ffwrapper{
class FormatIn;
class FormatOut;
-
- class CodedData;
}
namespace cffmpeg_wrap{
namespace buz{
- // 缂撳瓨鐨勮棰戝抚,绛夊緟fire瑙﹀彂寮�濮嬪綍鍍�
- typedef struct _cache_pkt{
- std::shared_ptr<ffwrapper::CodedData> data;
- int64_t id;
- }CPacket;
-
class Recorder{
public:
diff --git a/csrc/common.hpp b/csrc/common.hpp
new file mode 100644
index 0000000..e2a6064
--- /dev/null
+++ b/csrc/common.hpp
@@ -0,0 +1,16 @@
+#ifndef _cffmpeg_common_hpp_
+#define _cffmpeg_common_hpp_
+
+#include <stdint.h>
+#include <memory>
+
+namespace ffwrapper{
+ class CodedData;
+}
+// 缂撳瓨鐨勮棰戝抚
+typedef struct _cache_pkt{
+ std::shared_ptr<ffwrapper::CodedData> data;
+ int64_t id;
+}CPacket;
+
+#endif
\ No newline at end of file
diff --git a/csrc/ffmpeg/format/FormatIn.cpp b/csrc/ffmpeg/format/FormatIn.cpp
index 3f87d59..bdcaa53 100644
--- a/csrc/ffmpeg/format/FormatIn.cpp
+++ b/csrc/ffmpeg/format/FormatIn.cpp
@@ -17,8 +17,6 @@
#include "../configure/conf.hpp"
#include "../property/VideoProp.hpp"
-#include "../data/CodedData.hpp"
-#include "../data/FrameData.hpp"
#include "../../common/gpu/info.h"
@@ -147,37 +145,25 @@
vs_idx_ = i;
auto in = ctx_->streams[i];
- if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){
- fps_ = av_q2d(in->r_frame_rate);
- }else if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){
+ if(in->avg_frame_rate.num >=1 && in->avg_frame_rate.den >= 1){
fps_ = av_q2d(in->avg_frame_rate);
+ }else if(in->r_frame_rate.num >=1 && in->r_frame_rate.den >= 1){
+ fps_ = av_q2d(in->r_frame_rate);
}
- logIt("video stream time base %d : %d", in->time_base.num, in->time_base.den);
+ logIt("in stream fps %f, time_base: %d : %d", fps_, in->time_base.num, in->time_base.den);
}
if (type == AVMEDIA_TYPE_AUDIO){
as_idx_ = i;
- logIt("audio stream time base %d : %d", ctx_->streams[i]->time_base.num, ctx_->streams[i]->time_base.den);
}
}
+
return true;
}
- bool FormatIn::openCodec(const int type, AVDictionary **options){
- int stream_index = -1;
- switch(type){
- case AVMEDIA_TYPE_VIDEO:
- stream_index = vs_idx_;
- break;
- default:
- break;
- }
- if(stream_index < 0){
- logIt("open input %s codec need correct stream",ctx_->filename);
+ bool FormatIn::openCodec(AVDictionary **options){
+ if (vs_idx_ == -1) return false;
- return false;
- }
-
- AVStream *s = ctx_->streams[stream_index];
+ AVStream *s = ctx_->streams[vs_idx_];
AVCodecParameters *codecpar = s->codecpar;
AVCodec *dec = NULL;
@@ -267,9 +253,9 @@
return ctx_->streams[vs_idx_];
}
- if (type == ctx_->streams[vs_idx_]->codecpar->codec_type)
+ if (vs_idx_ > -1 && type == ctx_->streams[vs_idx_]->codecpar->codec_type)
return ctx_->streams[vs_idx_];
- if (type == ctx_->streams[as_idx_]->codecpar->codec_type)
+ if (as_idx_ > -1 && type == ctx_->streams[as_idx_]->codecpar->codec_type)
return ctx_->streams[as_idx_];
return NULL;
@@ -279,43 +265,31 @@
return dec_ctx_;
}
- bool FormatIn::isVideoPkt(AVPacket &pkt){
- if (pkt.stream_index == vs_idx_){
+ bool FormatIn::isVideoPkt(AVPacket *pkt){
+ if (pkt->stream_index == vs_idx_){
return true;
}
return false;
}
- bool FormatIn::isAudioPkt(AVPacket &pkt){
- if (pkt.stream_index == as_idx_){
+ bool FormatIn::isAudioPkt(AVPacket *pkt){
+ if (pkt->stream_index == as_idx_){
return true;
}
return false;
}
- bool FormatIn::readPacket(AVPacket &pkt_out){
+ int FormatIn::readPacket(AVPacket *pkt_out){
- const int ret = av_read_frame(ctx_, &pkt_out);
- if(ret < 0){
- return false;
- }
-
- return true;
-
+ return av_read_frame(ctx_, pkt_out);
}
- bool FormatIn::readPacket(std::shared_ptr<CodedData> &data){
-
- AVPacket &pkt(data->getAVPacket());
- return readPacket(pkt);
- }
-
- int FormatIn::decode(AVFrame* &frame, AVPacket &pkt){
+ int FormatIn::decode(AVFrame* frame, AVPacket *pkt){
AVStream *in = getStream();
- av_packet_rescale_ts(&pkt, in->time_base, in->codec->time_base);
- int ret = avcodec_send_packet(dec_ctx_, &pkt);
+ av_packet_rescale_ts(pkt, in->time_base, in->codec->time_base);
+ int ret = avcodec_send_packet(dec_ctx_, pkt);
if(ret < 0){
logIt("avcodec_send_packet error : %s", getAVErrorDesc(ret).c_str());
return -1;
@@ -328,39 +302,9 @@
logIt("decode frame failed : %s", getAVErrorDesc(ret).c_str());
return -1;
}else{
- return 1;
+ return 0;
}
}
- return 0;
+ return -2;
}
-
- int FormatIn::decode(std::shared_ptr<FrameData> &frame_data,
- std::shared_ptr<CodedData> &data){
-
- AVFrame *frame = frame_data->getAVFrame();
- AVPacket &pkt(data->getAVPacket());
-
- return decode(frame, pkt);
- }
-
- int FormatIn::readFrame(AVFrame* &frame){
-
- auto data(std::make_shared<CodedData>());
- if(!readPacket(data)){
- return -1;
- }
-
- AVPacket &pkt(data->getAVPacket());
-
- return decode(frame, pkt);
- }
-
- int FormatIn::readFrame(std::shared_ptr<FrameData> &frame_data){
-
- AVFrame *frame(frame_data->getAVFrame());
-
- return readFrame(frame);
- }
-
-
}
diff --git a/csrc/ffmpeg/format/FormatIn.hpp b/csrc/ffmpeg/format/FormatIn.hpp
index ca14f81..5514bc6 100644
--- a/csrc/ffmpeg/format/FormatIn.hpp
+++ b/csrc/ffmpeg/format/FormatIn.hpp
@@ -19,8 +19,6 @@
namespace ffwrapper{
class VideoProp;
- class CodedData;
- class FrameData;
class FormatIn
{
@@ -35,25 +33,20 @@
int open(const char *filename, AVDictionary **options);
bool findStreamInfo(AVDictionary **options);
- bool openCodec(const int type, AVDictionary **options);
+ bool openCodec(AVDictionary **options);
- bool readPacket(AVPacket &pkt_out);
- bool readPacket(std::shared_ptr<CodedData> &data);
+ int readPacket(AVPacket *pkt_out);
- int decode(AVFrame* &frame, AVPacket &pkt);
- int decode(std::shared_ptr<FrameData> &frame_data,
- std::shared_ptr<CodedData> &data);
+ int decode(AVFrame* frame, AVPacket *pkt);
- int readFrame(AVFrame* &frame);
- int readFrame(std::shared_ptr<FrameData> &frame_data);
-
- bool isVideoPkt(AVPacket &pkt);
- bool isAudioPkt(AVPacket &pkt);
+ bool isVideoPkt(AVPacket *pkt);
+ bool isAudioPkt(AVPacket *pkt);
private:
bool allocCodec(AVCodec *dec, AVStream *s, AVDictionary **options);
public:
AVStream *getStream(int type = -1);
AVCodecContext *getCodecContext(int type = 0);
+ AVFormatContext *getFromatContext(){return ctx_;}
const double getFPS()const{return fps_;}
private:
AVFormatContext *ctx_;
diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp
index 0c6958f..6b6c38e 100644
--- a/csrc/ffmpeg/format/FormatOut.cpp
+++ b/csrc/ffmpeg/format/FormatOut.cpp
@@ -16,8 +16,6 @@
#include "../configure/conf.hpp"
#include "../property/VideoProp.hpp"
-#include "../data/CodedData.hpp"
-#include "../data/FrameData.hpp"
#include "../../common/gpu/info.h"
@@ -26,13 +24,13 @@
namespace ffwrapper{
FormatOut::FormatOut()
:ctx_(NULL)
- ,v_s_(NULL)
+ ,v_idx_(-1)
+ ,a_idx_(-1)
,enc_ctx_(NULL)
,sync_opts_(0)
,record_(false)
,fps_(0.0f)
,format_name_("mp4")
- ,streams_(NULL)
{}
FormatOut::~FormatOut()
@@ -51,7 +49,6 @@
avformat_free_context(ctx_);
ctx_ = NULL;
}
- v_s_ = NULL;
sync_opts_ = 0;
}
@@ -152,7 +149,8 @@
}
logIt("use encoder %s", codec->name);
- v_s_ = avformat_new_stream(ctx_, codec);
+ AVStream *v = avformat_new_stream(ctx_, codec);
+ v_idx_ = 0;
enc_ctx_ = avcodec_alloc_context3(codec);
@@ -182,7 +180,7 @@
logIt("can't open output codec: %s", getAVErrorDesc(err).c_str());
return false;
}
- err = avcodec_parameters_from_context(v_s_->codecpar, enc_ctx_);
+ err = avcodec_parameters_from_context(v->codecpar, enc_ctx_);
if (err < 0) {
logIt("can't avcodec_parameters_from_context: %s", getAVErrorDesc(err).c_str());
return false;
@@ -197,20 +195,25 @@
return true;
}
+
+ AVStream *FormatOut::getStream(){
+ if (v_idx_ == -1) return NULL;
+ return ctx_->streams[v_idx_];
+ }
const AVCodecContext *FormatOut::getCodecContext()const{
return enc_ctx_;
}
- int FormatOut::encode(AVPacket &pkt, AVFrame *frame){
+ int FormatOut::encode(AVPacket *pkt, AVFrame *frame){
AVStream *out = getStream();
frame->quality = enc_ctx_->global_quality;
frame->pict_type = AV_PICTURE_TYPE_NONE;
- pkt.data = NULL;
- pkt.size = 0;
+ pkt->data = NULL;
+ pkt->size = 0;
int ret = avcodec_send_frame(enc_ctx_, frame);
if(ret < 0){
@@ -219,50 +222,26 @@
}
while(ret >= 0){
- ret = avcodec_receive_packet(enc_ctx_, &pkt);
+ ret = avcodec_receive_packet(enc_ctx_, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}else if (ret < 0) {
logIt("avcodec_receive_packet : %s", getAVErrorDesc(ret).c_str());
return -1;
}else{
- if(pkt.pts == AV_NOPTS_VALUE
+ if(pkt->pts == AV_NOPTS_VALUE
&& !(enc_ctx_->codec->capabilities & AV_CODEC_CAP_DELAY))
{
- pkt.pts = sync_opts_++;
+ pkt->pts = sync_opts_++;
}
- av_packet_rescale_ts(&pkt, enc_ctx_->time_base, out->time_base);
+ av_packet_rescale_ts(pkt, enc_ctx_->time_base, out->time_base);
// printf("pkt pts: %lld\n", pkt.pts);
- return 1;
+ return 0;
}
}
- return 0;
- }
-
- int FormatOut::encode(std::shared_ptr<CodedData> &data,
- std::shared_ptr<FrameData> &frame_data){
-
- AVStream *out = getStream();
- AVCodecContext *enc_ctx = out->codec;
- data->refExtraData(enc_ctx->extradata, enc_ctx->extradata_size);
-
- AVPacket &pkt(data->getAVPacket());
- AVFrame *frame = frame_data->getAVFrame();
-
- return encode(pkt, frame);
- }
-
- int FormatOut::encode(std::shared_ptr<CodedData> &data,AVFrame *frame){
-
- AVStream *out = getStream();
- AVCodecContext *enc_ctx = out->codec;
- data->refExtraData(enc_ctx->extradata, enc_ctx->extradata_size);
-
- AVPacket &pkt(data->getAVPacket());
-
- return encode(pkt, frame);
+ return -2;
}
//////////////////////////////////////////////////////////////////////////
@@ -296,12 +275,11 @@
return true;
}
- bool FormatOut::copyCodecFromIn(std::vector<AVStream*> in){
- auto count = in.size();
+ bool FormatOut::copyCodecFromIn(AVFormatContext* in){
- for(int i = 0; i < count; i++)
+ for(int i = 0; i < in->nb_streams; i++)
{ //鏍规嵁杈撳叆娴佸垱寤鸿緭鍑烘祦
- AVStream *in_stream = in[i];
+ AVStream *in_stream = in->streams[i];
AVStream *out_stream = avformat_new_stream(ctx_, in_stream->codec->codec);
if(!out_stream)
{
@@ -309,9 +287,6 @@
return false;
}
- if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
- v_s_ = out_stream;
- }
//灏嗚緭鍑烘祦鐨勭紪鐮佷俊鎭鍒跺埌杈撳叆娴�
auto ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if(ret<0)
@@ -319,19 +294,26 @@
logIt("Failed to copy context from input to output stream codec context\n");
return false;
}
- out_stream->codec->codec_tag = 0;
+ if (in_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
+ v_idx_ = i;
+ }else{
+ a_idx_ = i;
+ }
+
+ out_stream->codecpar->codec_tag = out_stream->codec->codec_tag = 0;
+
if(ctx_->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
- streams_ = in;
+ in_ctx_ = in;
return true;
}
- bool FormatOut::JustWriter(std::vector<AVStream*> in, const char *filename){
+ bool FormatOut::JustWriter(AVFormatContext *in, const char *filename){
if(ctx_){
clear();
}
@@ -345,6 +327,7 @@
}
flag = openResource(filename, 2);
+
if(flag){
AVDictionary *avdic = NULL;
char option_key[]="movflags";
@@ -354,6 +337,7 @@
av_dict_free(&avdic);
}
+
return flag;
}
@@ -393,114 +377,58 @@
getAVErrorDesc(ret).c_str());
return false;
}
+
record_ = true;
return true;
}
- void FormatOut::adjustVideoPTS(AVPacket &pkt, const int64_t &frame_cnt){
- int64_t time_stamp = frame_cnt;
-
- pkt.pos = -1;
- pkt.stream_index = 0;
-
- //Write PTS
- AVRational time_base = getStream()->time_base;
-
- AVRational time_base_q = { 1, AV_TIME_BASE };
- //Duration between 2 frames (us)
- // int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / fps_); //鍐呴儴鏃堕棿鎴�
- int64_t calc_duration = (int64_t)(AV_TIME_BASE / fps_); //鍐呴儴鏃堕棿鎴�
- //Parameters
- pkt.pts = av_rescale_q(time_stamp*calc_duration, time_base_q, time_base);
- pkt.dts = pkt.pts;
- pkt.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
-
- // logIt("FRAME ID: %lld, PTS : %lld, DTS : %lld", frame_cnt, pkt.pts, pkt.dts);
- }
-
- void FormatOut::adjustPTS(AVPacket &pkt, const int64_t &frame_cnt){
- if (streams_.size() == 1){
- return adjustVideoPTS(pkt, frame_cnt);
- }
-
- if (pkt.stream_index >= streams_.size()){
+ void FormatOut::adjustPTS(AVPacket *pkt, const int64_t &frame_cnt){
+ if (pkt->stream_index >= ctx_->nb_streams){
logIt("adjustPTS pkt stream index too much");
return;
}
AVStream *in_stream,*out_stream;
- in_stream = streams_[pkt.stream_index];
- out_stream = ctx_->streams[pkt.stream_index];
-
- // logIt("stream %d time_base %d : %d", pkt.stream_index, in_stream->time_base.num, in_stream->time_base.den);
- // logIt("out time_base %d : %d", out_stream->time_base.num, out_stream->time_base.den);
+ in_stream = in_ctx_->streams[pkt->stream_index];
+ out_stream = ctx_->streams[pkt->stream_index];
- std::string type("video");
- if (in_stream->codecpar->codec_type == 1){
- type = "audio";
- }
-
+ // if (type == "audio")
// logIt("BEFORE stream %d type: %s, pts: %lld, dts: %lld, duration: %lld",
// pkt.stream_index, type.c_str(), pkt.pts, pkt.pts, pkt.duration);
- //copy packet
- //杞崲 PTS/DTS 鏃跺簭
- pkt.pts = av_rescale_q_rnd(pkt.pts,in_stream->time_base,out_stream->time_base,(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
- pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
- //printf("pts %d dts %d base %d\n",pkt.pts,pkt.dts, in_stream->time_base);
- pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
- pkt.pos = -1;
+ //杞崲 PTS/DTS 鏃跺簭
+ pkt->pts = av_rescale_q_rnd(pkt->pts,in_stream->time_base,out_stream->time_base,(enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
+ pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, out_stream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
+ pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base);
+ pkt->pos = -1;
+
+ // if (type == "audio")
// logIt("AFTER stream %d type: %s, pts: %lld, dts: %lld, duration: %lld",
// pkt.stream_index, type.c_str(), pkt.pts, pkt.pts, pkt.duration);
-
- // //姝hile寰幆涓苟闈炴墍鏈塸acket閮芥槸瑙嗛甯э紝褰撴敹鍒拌棰戝抚鏃惰褰曚竴涓嬶紝浠呮鑰屽凡
- // if(pkt.stream_index==video_index)
- // {
- // printf("Receive %8d video frames from input URL\n",frame_index);
- // frame_index++;
- // }
-
- // //灏嗗寘鏁版嵁鍐欏叆鍒版枃浠躲��
- // ret = av_interleaved_write_frame(ofmt_ctx,&pkt);
- // if(ret < 0)
- // {
- // /**
- // 褰撶綉缁滄湁闂鏃讹紝瀹规槗鍑虹幇鍒拌揪鍖呯殑鍏堝悗涓嶄竴鑷达紝pts鏃跺簭娣蜂贡浼氬鑷�
- // av_interleaved_write_frame鍑芥暟鎶� -22 閿欒銆傛殏鏃跺厛涓㈠純杩欎簺杩熸潵鐨勫抚鍚�
- // 鑻ユ墍澶ч儴鍒嗗寘閮芥病鏈塸ts鏃跺簭锛岄偅灏辫鐪嬫儏鍐佃嚜宸辫ˉ涓婃椂搴忥紙姣斿杈冨墠涓�甯ф椂搴�+1锛夊啀鍐欏叆銆�
- // */
- // if(ret==-22){
- // continue;
- // }else{
- // printf("Error muxing packet.error code %d\n" , ret);
- // break;
- // }
-
- // }
}
- bool FormatOut::writeFrame(AVPacket &pkt, const int64_t &frame_cnt,
+ bool FormatOut::writeFrame(AVPacket *pkt, const int64_t &frame_cnt,
bool interleaved/* = true*/){
adjustPTS(pkt, frame_cnt);
auto ret = writeFrame2(pkt, interleaved);
if (!ret){
logIt("write to file failed, pkt.pts: %lld, dts: %lld, frame count: %d",
- pkt.pts, pkt.dts, frame_cnt);
+ pkt->pts, pkt->dts, frame_cnt);
}
return ret;
}
- bool FormatOut::writeFrame2(AVPacket &pkt, bool interleaved){
+ bool FormatOut::writeFrame2(AVPacket *pkt, bool interleaved){
int ret = 0;
if(interleaved){
- ret = av_interleaved_write_frame(ctx_, &pkt);
+ ret = av_interleaved_write_frame(ctx_, pkt);
}else{
// returns 1 if flushed and there is no more data to flush
- ret = av_write_frame(ctx_, &pkt);
+ ret = av_write_frame(ctx_, pkt);
}
if(ret < -22 || ret == 0){
diff --git a/csrc/ffmpeg/format/FormatOut.hpp b/csrc/ffmpeg/format/FormatOut.hpp
index 2fbe47b..fc6fa1b 100644
--- a/csrc/ffmpeg/format/FormatOut.hpp
+++ b/csrc/ffmpeg/format/FormatOut.hpp
@@ -15,8 +15,6 @@
namespace ffwrapper{
class VideoProp;
- class CodedData;
- class FrameData;
class FormatOut
{
@@ -34,28 +32,24 @@
bool open(const char *filename, const char *format_name);
bool openCodec(VideoProp &prop);
- int encode(AVPacket &pkt, AVFrame *frame);
- int encode(std::shared_ptr<CodedData> &data,
- std::shared_ptr<FrameData> &frame_data);
- int encode(std::shared_ptr<CodedData> &data,AVFrame *frame);
+ int encode(AVPacket *pkt, AVFrame *frame);
public:
- bool copyCodecFromIn(std::vector<AVStream*> in);
+ bool copyCodecFromIn(AVFormatContext* in);
bool openResource(const char *filename, const int flags);
bool closeResource();
- bool JustWriter(std::vector<AVStream*> in, const char *filename);
+ bool JustWriter(AVFormatContext* in, const char *filename);
bool EncodeWriter(const char *filename);
- bool writeFrame(AVPacket &pkt, const int64_t &frame_cnt, bool interleaved = true);
- void adjustPTS(AVPacket &pkt, const int64_t &frame_cnt);
- void adjustVideoPTS(AVPacket &pkt, const int64_t &frame_cnt);
+ bool writeFrame(AVPacket *pkt, const int64_t &frame_cnt, bool interleaved = true);
+ void adjustPTS(AVPacket *pkt, const int64_t &frame_cnt);
bool endWriter();
bool writeHeader(AVDictionary **options = NULL);
- bool writeFrame2(AVPacket &pkt, bool interleaved);
+ bool writeFrame2(AVPacket *pkt, bool interleaved);
bool writeTrailer();
public:
- AVStream *getStream(){return v_s_;}
+ AVStream *getStream();
const AVCodecContext *getCodecContext() const;
const double getFPS()const{return fps_;}
@@ -67,7 +61,8 @@
void configEncoder(VideoProp &prop);
private:
AVFormatContext *ctx_;
- AVStream *v_s_;
+ int v_idx_;
+ int a_idx_;
AVCodecContext *enc_ctx_;
int64_t sync_opts_;
@@ -78,7 +73,7 @@
std::string format_name_;
// rec
- std::vector<AVStream*> streams_;
+ AVFormatContext *in_ctx_;
};
}
#endif
\ No newline at end of file
diff --git a/csrc/worker/decoder.cpp b/csrc/worker/decoder.cpp
index 4cd1f8d..4211b41 100644
--- a/csrc/worker/decoder.cpp
+++ b/csrc/worker/decoder.cpp
@@ -10,6 +10,7 @@
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
+#include <libavcodec/avcodec.h>
}
using namespace ffwrapper;
@@ -23,18 +24,33 @@
,conv_h_(h)
,conv_flag_(f)
,decRef_(dec)
+ ,thread_(nullptr)
+ ,stop_{false}
{}
decoder::~decoder(){
+ if (thread_){
+ stop_.store(true);
+ thread_->join();
+ }
+
if (conv_){
delete conv_;
}
- std::lock_guard<std::mutex> l(mutex_pic_);
- for(auto &i : list_pic_){
- free(i.data);
+
+ {
+ std::lock_guard<std::mutex> l(mutex_pkt_);
+ list_pkt_.clear();
}
- list_pic_.clear();
+
+ {
+ std::lock_guard<std::mutex> l(mutex_pic_);
+ for(auto &i : list_pic_){
+ free(i.data);
+ }
+ list_pic_.clear();
+ }
}
int decoder::initDecoder(){
@@ -43,7 +59,7 @@
if(decRef_->getCodecContext() == NULL){
bool flag = true;
- flag = decRef_->openCodec(AVMEDIA_TYPE_VIDEO, NULL);
+ flag = decRef_->openCodec(NULL);
auto dec_ctx = decRef_->getCodecContext();
if(conv_){
delete conv_;
@@ -64,40 +80,96 @@
return 0;
}
- int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
- if (!data) return -1;
- if (decRef_->isAudioPkt(data->getAVPacket())) return -2;
-
- if (!conv_){
- initDecoder();
- }
- auto frame(std::make_shared<FrameData>());
- auto ret = decRef_->decode(frame, data);
- if(ret == 1){
- //缂撳瓨鏁版嵁
- BGR24 pic;
- AVFrame *frm = frame->getAVFrame();
- pic.w = conv_w_;
- pic.h = conv_h_;
- unsigned char *picData = (unsigned char*)malloc(pic.w * pic.h * 3);
- conv_->copyPicture(picData, frm);
- pic.data = picData;
- pic.id = id;
-
- std::lock_guard<std::mutex> l(mutex_pic_);
- while(list_pic_.size() > 10){
- for(int i = 0; i < 5; i++){
- auto t = list_pic_.front();
- free(t.data);
- list_pic_.pop_front();
- }
+ int decoder::saveFrame(AVFrame *frame, int64_t &id){
+ //缂撳瓨鏁版嵁
+ BGR24 pic;
+ AVFrame *frm = frame;
+ pic.w = conv_w_;
+ pic.h = conv_h_;
+ unsigned char *picData = (unsigned char*)malloc(pic.w * pic.h * 3);
+ conv_->copyPicture(picData, frm);
+ pic.data = picData;
+ pic.id = id;
+ std::lock_guard<std::mutex> l(mutex_pic_);
+ while(list_pic_.size() > 50){
+ for(int i = 0; i < 12; i++){
+ auto t = list_pic_.front();
+ free(t.data);
+ list_pic_.pop_front();
}
- list_pic_.emplace_back(pic);
-
}
+ list_pic_.emplace_back(pic);
return list_pic_.size();
}
+ void decoder::Start(){
+ if (thread_) return;
+ thread_.reset(new std::thread([&]{
+ if (initDecoder() != 0) {
+ return;
+ }
+
+ while(!stop_.load()){
+
+ std::unique_lock<std::mutex> locker(mutex_pkt_);
+ cv_.wait(locker, [&]{
+ return !list_pkt_.empty() || stop_.load();
+ });
+ if (stop_.load()){
+ break;
+ }
+
+ auto pkt = list_pkt_.front();
+ list_pkt_.pop_front();
+
+ AVFrame *frame = av_frame_alloc();
+ AVPacket np(pkt.data->getAVPacket());
+ av_copy_packet(&np, &pkt.data->getAVPacket());
+
+ auto ret = decRef_->decode(frame, &np);
+ av_packet_unref(&np);
+
+ if (ret == 0){
+ saveFrame(frame, pkt.id);
+ }
+ av_frame_free(&frame);
+ }
+
+ }));
+ }
+
+ int decoder::SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
+
+ if (!data) return -1;
+ if (decRef_->isAudioPkt(&data->getAVPacket())) return -2;
+
+ // if (!thread_){
+ // if (initDecoder() != 0) return -3;
+ // Start();
+ // }
+
+ // std::lock_guard<std::mutex> l(mutex_pkt_);
+ // list_pkt_.push_back({data, id});
+ // cv_.notify_one();
+ // return list_pkt_.size();
+
+ if (!conv_){
+ if (initDecoder() != 0) return -3;
+ }
+
+ AVFrame *frame = av_frame_alloc();
+ AVPacket np(data->getAVPacket());
+ av_copy_packet(&np, &data->getAVPacket());
+ auto ret = decRef_->decode(frame, &np);
+ av_packet_unref(&np);
+
+ if (ret == 0){
+ saveFrame(frame, id);
+ }
+ av_frame_free(&frame);
+
+ }
+
void decoder::GetFrame(unsigned char **data, int *w, int *h, int64_t *id){
std::lock_guard<std::mutex> l(mutex_pic_);
if(list_pic_.empty()){
diff --git a/csrc/worker/decoder.hpp b/csrc/worker/decoder.hpp
index 0f3f76a..3bb3a18 100644
--- a/csrc/worker/decoder.hpp
+++ b/csrc/worker/decoder.hpp
@@ -5,12 +5,19 @@
#include <memory>
#include <list>
#include <mutex>
+#include <thread>
+#include <atomic>
+#include <condition_variable>
+
+#include "../common.hpp"
+
+struct AVFrame;
namespace ffwrapper
{
class FormatIn;
class cvbridge;
- class CodedData;
+
} // namespace ffwrapper
namespace cffmpeg_wrap
@@ -34,9 +41,17 @@
std::list<BGR24> list_pic_;
std::mutex mutex_pic_;
+ std::unique_ptr<std::thread> thread_;
+ std::atomic_bool stop_;
+
+ std::list<CPacket> list_pkt_;
+ std::mutex mutex_pkt_;
+ std::condition_variable cv_;
private:
int initDecoder();
+ int saveFrame(AVFrame *frame, int64_t &id);
public:
+ void Start();
int SetFrame(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
void GetFrame(unsigned char **data, int *w, int *h, int64_t *id);
public:
diff --git a/csrc/worker/rec.cpp b/csrc/worker/rec.cpp
index 797e047..d7ce012 100644
--- a/csrc/worker/rec.cpp
+++ b/csrc/worker/rec.cpp
@@ -3,6 +3,10 @@
#include <unistd.h>
#include <sys/time.h>
+extern "C"{
+#include <libavcodec/avcodec.h>
+}
+
#include "../ffmpeg/format/FormatIn.hpp"
#include "../ffmpeg/data/CodedData.hpp"
#include "../ffmpeg/log/log.hpp"
@@ -181,12 +185,14 @@
std::lock_guard<std::mutex> l(mtx_pkt_);
//wait I
if (list_pkt_.empty()) {
- AVPacket &avpkt = data->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
+
+ if (!(data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
return;
}
}
+
list_pkt_.push_back({data, id});
+
// 瓒呰繃缂撳瓨鏈�澶ч暱搴�,鍒犻櫎涓�涓猤op
shrinkCache();
}
@@ -194,12 +200,12 @@
int rec::shrinkCache(){
//瓒呰繃鏈�澶х紦瀛�,涓㈠純gop
//缂撳瓨鏈�灏忛暱搴︾殑,鐢ㄤ簬璁板綍
- while (list_pkt_.size() > minduration_/2) {
+ int md = minduration_ < 201 ? 200 : minduration_;
+ while (list_pkt_.size() > md/2) {
list_pkt_.pop_front();
while(!list_pkt_.empty()){
- auto &cache = list_pkt_.front();
- AVPacket &avpkt = cache.data->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
+ auto &i = list_pkt_.front();
+ if (!(i.data->getAVPacket().flags & AV_PKT_FLAG_KEY)){
list_pkt_.pop_front();
}else{
break;
diff --git a/csrc/worker/rec.hpp b/csrc/worker/rec.hpp
index 5ac00a9..a19ea29 100644
--- a/csrc/worker/rec.hpp
+++ b/csrc/worker/rec.hpp
@@ -2,12 +2,13 @@
#define _cffmpeg_rec_hpp_
#include <string>
-#include <memory>
#include <unordered_map>
#include <list>
#include <mutex>
#include "../buz/recorder.hpp"
+
+struct AVPacket;
namespace ffwrapper
{
@@ -41,7 +42,7 @@
std::mutex mtx_recInfo_;
// 缂撳瓨鐨勮棰戝抚,绛夊緟firerecsignal瑙﹀彂寮�濮嬪綍鍍�
- std::list<buz::CPacket> list_pkt_;
+ std::list<CPacket> list_pkt_;
// 澶氱嚎绋�,鐢熶骇鑰呯嚎绋媟eader push pkt,娑堣垂鑰�,褰曞儚绾跨▼pop
std::mutex mtx_pkt_;
diff --git a/csrc/worker/stream.cpp b/csrc/worker/stream.cpp
index 1828304..9fe11da 100644
--- a/csrc/worker/stream.cpp
+++ b/csrc/worker/stream.cpp
@@ -1,7 +1,11 @@
#include "stream.hpp"
-#include "../ffmpeg/data/CodedData.hpp"
+extern "C"{
+#include <libavcodec/avcodec.h>
+}
+
#include "../ffmpeg/format/FormatIn.hpp"
+#include "../ffmpeg/data/CodedData.hpp"
namespace cffmpeg_wrap{
stream::stream(ffwrapper::FormatIn *in, const int maxSize)
@@ -12,50 +16,42 @@
stream::~stream(){
std::lock_guard<std::mutex> locker(mutex_avpkt_);
- list_avpkt_.clear();
+ list_pkt_.clear();
}
- int stream::SetPacket(std::shared_ptr<ffwrapper::CodedData> data){
+ int stream::SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
if (data){
- auto audio = streamRef_->isAudioPkt(data->getAVPacket());
// 濡傛灉鍖呮槸闊抽鍖�,浣嗘槸涓嶄娇鐢ㄩ煶棰�,鐩存帴杩斿洖
- if (!audio_ && audio){
+ if (!audio_ && streamRef_->isAudioPkt(&data->getAVPacket())){
return 0;
}
std::lock_guard<std::mutex> locker(mutex_avpkt_);
- list_avpkt_.push_back(data);
+ list_pkt_.push_back({data, id});
- while(list_avpkt_.size() > max_size_){
- list_avpkt_.pop_front();
- while(!list_avpkt_.empty()){
- auto &cache = list_avpkt_.front();
- AVPacket &avpkt = cache->getAVPacket();
- if (!(avpkt.flags & AV_PKT_FLAG_KEY)){
- list_avpkt_.pop_front();
- }else{
- break;
- }
- }
+ while(list_pkt_.size() > max_size_/2*3){
+ list_pkt_.pop_front();
}
- return list_avpkt_.size();
+
+ return list_pkt_.size();
}
return 0;
}
void stream::GetPacket(unsigned char **pktData, int *size, int *key){
std::lock_guard<std::mutex> l(mutex_avpkt_);
- if(list_avpkt_.empty()){
+ if(list_pkt_.empty()){
return;
}
- auto data = list_avpkt_.front();
- auto pkt = data->getAVPacket();
+
+ auto data = list_pkt_.front();
+ list_pkt_.pop_front();
+
+ auto pkt = data.data->getAVPacket();
*key = pkt.flags & AV_PKT_FLAG_KEY;
*size = pkt.size;
*pktData = (unsigned char *)malloc(*size);
memcpy(*pktData, pkt.data, pkt.size);
-
- list_avpkt_.pop_front();
}
}
\ No newline at end of file
diff --git a/csrc/worker/stream.hpp b/csrc/worker/stream.hpp
index b738ada..5c75d26 100644
--- a/csrc/worker/stream.hpp
+++ b/csrc/worker/stream.hpp
@@ -5,16 +5,17 @@
#include <mutex>
#include <memory>
+#include "../common.hpp"
+
namespace ffwrapper{
class FormatIn;
- class CodedData;
}
namespace cffmpeg_wrap{
class stream
{
private:
- std::list<std::shared_ptr<ffwrapper::CodedData> > list_avpkt_;
+ std::list<CPacket> list_pkt_;
std::mutex mutex_avpkt_;
ffwrapper::FormatIn *streamRef_;
const int max_size_;
@@ -23,7 +24,7 @@
stream(ffwrapper::FormatIn *in, const int maxSize);
~stream();
- int SetPacket(std::shared_ptr<ffwrapper::CodedData> data);
+ int SetPacket(std::shared_ptr<ffwrapper::CodedData> data, int64_t &id);
void GetPacket(unsigned char **pktData, int *size, int *key);
void AudioSwitch(const bool a){audio_ = a;}
};
diff --git a/csrc/wrapper.cpp b/csrc/wrapper.cpp
index 9f0e4e7..757f0bb 100644
--- a/csrc/wrapper.cpp
+++ b/csrc/wrapper.cpp
@@ -13,9 +13,8 @@
#include "ffmpeg/configure/conf.hpp"
#include "ffmpeg/format/FormatIn.hpp"
#include "ffmpeg/format/FormatOut.hpp"
-#include "ffmpeg/property/VideoProp.hpp"
#include "ffmpeg/data/CodedData.hpp"
-#include "ffmpeg/data/FrameData.hpp"
+#include "ffmpeg/property/VideoProp.hpp"
#include "ffmpeg/log/log.hpp"
#include "ffmpeg/bridge/cvbridge.hpp"
@@ -127,20 +126,21 @@
void Wrapper::init_worker(ffwrapper::FormatIn *in){
if (rec_->Loaded() && stream_ && decoder_) return;
+
stream_ = new stream(in, 3 * 25);
stream_->AudioSwitch(audio_);
decoder_ = new decoder(in, scale_w_, scale_h_, scale_f_);
-
+
rec_->Load(in);
if(fn_rec_lazy_) fn_rec_lazy_(in);
}
void Wrapper::run_worker(ffwrapper::FormatIn *in, std::shared_ptr<ffwrapper::CodedData> data, int64_t &id){
- if (stream_) stream_->SetPacket(data);
- if (decoder_) decoder_->SetFrame(data, id);
+ if (stream_) stream_->SetPacket(data, id);
if (rec_->Loaded()) rec_->SetPacket(data, id);
+ if (decoder_) decoder_->SetFrame(data, id);
}
void Wrapper::deinit_worker(){
@@ -160,17 +160,23 @@
continue;
}
+ int wTime = 1000000.0 / in->getFPS() ;
+ wTime >>= 1;
+ logIt("INPUT FPS: %d", wTime);
+
init_worker(in.get());
int64_t id = 0;
while(!stop_stream_.load()){
auto data(std::make_shared<CodedData>());
- if(!in->readPacket(data)){
- logIt("read packet error");
+ if (in->readPacket(&data->getAVPacket()) != 0){
+ logIt("read packet error, id: %lld", id);
break;
- }
-
+ }
+
run_worker(in.get(), data, id);
+ usleep(wTime);
+
id++;
}
@@ -237,7 +243,7 @@
logIt("yolo can't find video stream\n");
return NULL;
}
- auto flag = in->openCodec(AVMEDIA_TYPE_VIDEO, NULL);
+ auto flag = in->openCodec(NULL);
if(flag){
auto dec_ctx = in->getCodecContext();
@@ -255,22 +261,20 @@
return NULL;
}
- auto data(std::make_shared<CodedData>());
- if(!in->readPacket(data)){
- logIt("read packet error");
- return NULL;
+ uint8_t *data = NULL;
+ AVPacket *pkt = av_packet_alloc();
+ if(in->readPacket(pkt) == 0){
+ AVFrame *frm = av_frame_alloc();
+ if(in->decode(frm, pkt) == 0){
+ *w = frm->width;
+ *h = frm->height;
+ data = (unsigned char*)malloc(frm->width * frm->height * 3);
+ bridge_->copyPicture(data, frm);
+ }
+ av_frame_free(&frm);
+ av_packet_free(&pkt);
}
- auto frame(std::make_shared<FrameData>());
- auto ret = in->decode(frame, data);
- if(ret == 1){
- AVFrame *frm = frame->getAVFrame();
- *w = frm->width;
- *h = frm->height;
- unsigned char *data = (unsigned char*)malloc(frm->width * frm->height * 3);
- bridge_->copyPicture(data, frm);
- return data;
- }
- return NULL;
+ return data;
}
/////// for encoder
typedef struct _PicEncoder{
@@ -334,28 +338,28 @@
}
AVFrame *frame = e->bridge->getAVFrame(in, w, h);
- auto data(std::make_shared<CodedData>());
+ AVPacket *pkt = av_packet_alloc();
- const int flag = e->enc->encode(data, frame);
- if(flag > 0){
- auto pkt = data->getAVPacket();
+ auto flag = e->enc->encode(pkt, frame);
+ if(flag == 0){
int extradata_size = ctx->extradata_size;
uint8_t *extra = ctx->extradata;
- *key = pkt.flags & AV_PKT_FLAG_KEY;
+ *key = pkt->flags & AV_PKT_FLAG_KEY;
if(!(*key)){
extradata_size = 0;
}
- *size = pkt.size + extradata_size;
+ *size = pkt->size + extradata_size;
*out = (unsigned char *)malloc(*size);
memcpy(*out, extra, extradata_size);
- memcpy(*out + extradata_size, pkt.data, pkt.size);
+ memcpy(*out + extradata_size, pkt->data, pkt->size);
}else{
logIt("encode error or need more packet\n");
}
+ av_packet_free(&pkt);
av_frame_free(&frame);
return flag;
diff --git a/csrc/wrapper.hpp b/csrc/wrapper.hpp
index 3b4aa7b..c6fc3ea 100644
--- a/csrc/wrapper.hpp
+++ b/csrc/wrapper.hpp
@@ -1,10 +1,6 @@
#ifndef _cffmpeg_wrapper_hpp_
#define _cffmpeg_wrapper_hpp_
-extern "C"{
-#include <libavcodec/avcodec.h>
-}
-
#include <stdint.h>
#include <string>
@@ -16,11 +12,11 @@
#include "common/callback.hpp"
+
namespace ffwrapper{
class FormatIn;
-
- class VideoProp;
class CodedData;
+ class VideoProp;
}
namespace cffmpeg_wrap{
--
Gitblit v1.8.0