From 1d2e7ce97e33c74a949d443a226df531fbf5c7dd Mon Sep 17 00:00:00 2001
From: zhangmeng <775834166@qq.com>
Date: 星期三, 25 九月 2019 14:04:09 +0800
Subject: [PATCH] bug fix

---
 csrc/ffmpeg/format/FormatOut.cpp |  202 +++++++++++++++++++++++++-------------------------
 1 files changed, 100 insertions(+), 102 deletions(-)

diff --git a/csrc/ffmpeg/format/FormatOut.cpp b/csrc/ffmpeg/format/FormatOut.cpp
index bc77524..dce3f7e 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,7 +24,8 @@
 namespace ffwrapper{
 	FormatOut::FormatOut()
 	:ctx_(NULL)
-	,v_s_(NULL)
+    ,v_idx_(-1)
+	,a_idx_(-1)
     ,enc_ctx_(NULL)
     ,sync_opts_(0)
     ,record_(false)
@@ -50,7 +49,6 @@
             avformat_free_context(ctx_);
             ctx_ = NULL;
         }
-        v_s_ = NULL;
         sync_opts_ = 0;
 
     }
@@ -151,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);
 
@@ -181,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;
@@ -196,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){
@@ -218,89 +222,39 @@
         }
     
         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;
     }
 
 //////////////////////////////////////////////////////////////////////////
-    FormatOut::FormatOut(AVStream *in, const char *format_name)
+    FormatOut::FormatOut(const double fps, const char *format_name)
     :FormatOut(){
 
         format_name_ = format_name;
 
-        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){
-            fps_ = av_q2d(in->avg_frame_rate);
-        }
-    }
-
-    
-    bool FormatOut::copyCodecFromIn(AVStream *in){
-
-        v_s_ = avformat_new_stream(ctx_, in->codec->codec);
-        if(!v_s_){
-            return false;
-        }
-
-        int ret = avcodec_copy_context(v_s_->codec, in->codec);
-        if (ret < 0){
-            logIt("can't copy codec from in error:%s", getAVErrorDesc(ret).c_str()); 
-
-            return false;
-        }
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
-        if (ctx_->oformat->flags & AVFMT_GLOBALHEADER)  
-        {  
-            v_s_->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;  
-        }  
-        return true;
+        fps_ = fps;
     }
 
     bool FormatOut::openResource(const char *filename, const int flags){
-        if((ctx_->flags & AVFMT_NOFILE) != AVFMT_NOFILE){
+        if((ctx_->oformat->flags & AVFMT_NOFILE) != AVFMT_NOFILE){
             
             const int err = avio_open2(&ctx_->pb, filename, flags, NULL, NULL);
             if(err < 0)
@@ -320,7 +274,46 @@
         }
         return true;
     }
-    bool FormatOut::JustWriter(AVStream *in, const char *filename){
+
+    bool FormatOut::copyCodecFromIn(AVFormatContext* in){
+
+        for(int i = 0; i < in->nb_streams; i++)
+        {    //鏍规嵁杈撳叆娴佸垱寤鸿緭鍑烘祦
+            AVStream *in_stream = in->streams[i];
+            AVStream *out_stream = avformat_new_stream(ctx_, in_stream->codec->codec);
+            if(!out_stream)
+            {
+                logIt("Failed allocating output stream.\n");
+                return false;
+            }
+
+            //灏嗚緭鍑烘祦鐨勭紪鐮佷俊鎭鍒跺埌杈撳叆娴�
+            auto ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
+            if(ret<0)
+            {
+                logIt("Failed to copy context from input to output stream codec context\n");
+                return false;
+            }
+
+            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;
+
+        }
+
+        in_ctx_ = in;
+
+        return true;
+    }
+
+    bool FormatOut::JustWriter(AVFormatContext *in, const char *filename){
         if(ctx_){
             clear();
         }
@@ -334,6 +327,7 @@
         }
 
         flag = openResource(filename, 2);
+        
         if(flag){
             AVDictionary *avdic = NULL;
             char option_key[]="movflags";
@@ -343,6 +337,7 @@
             av_dict_free(&avdic);
 
         }
+        
         return flag;
     }
     
@@ -364,6 +359,7 @@
     bool FormatOut::endWriter(){
 
         auto flag =  writeTrailer();
+        closeResource();
         record_ = false;
 
         return flag;
@@ -381,60 +377,62 @@
                     getAVErrorDesc(ret).c_str()); 
             return false;
         }
+        
         record_ = true;
         return true;
     }
 
-    void FormatOut::adjustPTS(AVPacket &pkt, const int64_t &frame_cnt){
-        int64_t time_stamp = frame_cnt;
-        
-        pkt.pos = -1;  
-        pkt.stream_index = 0;
+    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;
+        }
 
-        //Write PTS
-        AVRational time_base = getStream()->time_base;
+        AVStream *in_stream,*out_stream;
         
-        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));
+        in_stream = in_ctx_->streams[pkt->stream_index];
+        out_stream = ctx_->streams[pkt->stream_index];
         
-        // if (pkt.duration < 0 || time_base.den != 90000){
-            // logIt("CALCULATE DURATION : %lld, fame count : %lld, TIMEBASE: %d", calc_duration,time_stamp, time_base.den);
-        // }
-        
+        // logIt("BEFORE stream %d, pts: %lld, dts: %lld, duration: %lld", 
+        // pkt->stream_index, pkt->pts, pkt->dts, pkt->duration);
+
+        //杞崲 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;  
+
+        // logIt("AFTER stream %d, pts: %lld, dts: %lld, duration: %lld", 
+        // pkt->stream_index, pkt->pts, pkt->dts, pkt->duration);
     }
 
-    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);
-        return writeFrame2(pkt, interleaved);
+        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);
+        }
+        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);
-        else
-        {
+        if(interleaved){
+            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 < 0)
-        {
-            logIt("write packet to file failed:%s",
-                    getAVErrorDesc(ret).c_str()); 
-            return false;
+        if(ret < -22 || ret == 0){
+            return true;
         }
 
-        return true;
+        return false;
     }
 
     bool FormatOut::writeTrailer(){

--
Gitblit v1.8.0