//Author: shibaorong
//Date: 2021.5.23
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#include <libavutil/frame.h>
#include <libavutil/mem.h>
#include <libswscale/swscale.h>
#include <libavcodec/avcodec.h>
#include <libavutil/dict.h>
#ifdef __cplusplus
}
#endif
class FfmpegStreamChr{
public:
AVFormatContext* format_context_;
AVStream * video_st;
AVStream * out_stream;
AVCodec* codec_;
AVCodecContext* codec_context_;
AVFrame* yuv_frame_;
AVFormatContext * pOutFmtContext;
AVPacket* packet_;
cv::Mat TempImg;
SwsContext* y2r_sws_context_;
uchar ** rgb_data_;//need
int* rgb_line_size_;//need
int video_stream_index_;
int audio_stream_index_;
int duration;
int width_;
int height_;
int bg_pts;
int ret;
int video_frame_size;
int audio_frame_size;
int video_frame_count;
int audio_frame_count;
//bool pts_first;
bool Decode(const char *,const char *);
//bool DecodeToImage();
static int custom_interrupt_callback(void *){
std::cout<<"chaoshi"<<std::endl;
return 0;
};
FfmpegStreamChr(){
this->format_context_=avformat_alloc_context();
this->format_context_->interrupt_callback.callback=custom_interrupt_callback;
this->format_context_->interrupt_callback.opaque=this;
rgb_data_=new uchar* [sizeof(uint8_t *)* 8];
rgb_line_size_=new int[sizeof(int)*8];
packet_=av_packet_alloc();
video_frame_size=0;
audio_frame_size=0;
video_frame_count=0;
audio_frame_count=0;
}
};
bool FfmpegStreamChr::Decode(const char *pstrFilename,const char* out_file){
avformat_network_init();
//视频流地址
std::string tempfile=pstrFilename;
if(avformat_open_input(&format_context_,tempfile.c_str(),NULL,NULL)<0)return false;
//从媒体文件中读包进而获取流消息
if(avformat_find_stream_info(format_context_,nullptr)<0)return false;
//打印
av_dump_format(format_context_,0,tempfile.c_str(),0);
ret=avformat_alloc_output_context2(&pOutFmtContext,NULL,NULL,out_file);
if(ret<0){
printf("avformat_alloc_output_context2 filed:%d\n",ret);
return false;
}
for(int i=0;i<format_context_->nb_streams;i++){
video_st=format_context_->streams[i];
//筛选视频流和音频流
if(video_st->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){
video_stream_index_=i;
}
if(video_st->codecpar->codec_type==AVMEDIA_TYPE_AUDIO){
audio_stream_index_=i;
}
//找到对应的解码器
codec_=avcodec_find_decoder(video_st->codecpar->codec_id);
out_stream=avformat_new_stream(pOutFmtContext,codec_);
//创建解码器对应的结构体
AVCodecContext* codec_ctx=avcodec_alloc_context3(codec_);
ret=avcodec_parameters_to_context(codec_ctx,video_st->codecpar);
if(ret<0){
printf("Failed to copy in_stream codecpar to codec context\n");
return false;
}
codec_ctx->codec_tag=0;
codec_ctx->codec_tag = 0;
if (pOutFmtContext->oformat->flags & AVFMT_GLOBALHEADER)
codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret=avcodec_parameters_from_context(out_stream->codecpar,codec_ctx);
if(ret<0){
printf("Failed to copy codec context to out_stream codecpar context\n");
return false;
}
}
av_dump_format(pOutFmtContext, 0, out_file, 1);
ret = avio_open(&pOutFmtContext->pb, out_file, AVIO_FLAG_WRITE);
if(ret < 0){
printf("avio_open failed\n");
return -1;
}
ret = avformat_write_header(pOutFmtContext, NULL);
if( ret < 0){
printf("avformat_write_header failed\n");
return -1;
}
while(1){
//6.读取数据包
ret=av_read_frame(format_context_,packet_);
if(ret<0)break;
video_st=format_context_->streams[packet_->stream_index];
out_stream=pOutFmtContext->streams[packet_->stream_index];
av_packet_rescale_ts(packet_,video_st->time_base,out_stream->time_base);
if(packet_->stream_index==video_stream_index_){
video_frame_size+=packet_->size;
printf("recv %5d video frame %5d-%5d\n", ++video_frame_count, packet_->size, video_frame_size);
}
if(packet_->stream_index==audio_stream_index_){
audio_frame_size+=packet_->size;
printf("recv %5d audio frame %5d-%5d\n", ++audio_frame_count, packet_->size, audio_frame_size);
}
ret=av_interleaved_write_frame(pOutFmtContext,packet_);
if(ret<0){
printf("av_interleaved_write_frame failed\n");
break;
}
av_packet_unref(packet_);
}
av_write_trailer(pOutFmtContext);
av_packet_free(&packet_);
avformat_close_input(&format_context_);
avio_close(pOutFmtContext->pb);
avformat_free_context(pOutFmtContext);
printf("................end\n");
return true;
};
int main()
{
const char* s="rtmp://58.200.131.2:1935/livetv/hunantv";
const char* o="outfile.flv";
FfmpegStreamChr* f=new FfmpegStreamChr();
bool res=f->Decode(s,o);
std::cout<<res;
return 0;
}