|
@@ -0,0 +1,446 @@
|
|
|
+#include <QCoreApplication>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+extern "C"
|
|
|
+{
|
|
|
+#include <libavcodec/avcodec.h>
|
|
|
+#include <libavutil/opt.h>
|
|
|
+#include <libavutil/imgutils.h>
|
|
|
+#include <libavutil/common.h>
|
|
|
+#include "libavutil/error.h"
|
|
|
+#include "libavutil/hwcontext.h"
|
|
|
+#include "libavformat/avformat.h"
|
|
|
+#include "libavformat/avio.h"
|
|
|
+
|
|
|
+#ifdef USE_QSV
|
|
|
+//#include "libavutil/hwcontext_qsv.h"
|
|
|
+
|
|
|
+//#include "libavutil/hwcontext_vaapi.h"
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+//AVCodec *pCodec=NULL; //解码器指针
|
|
|
+//AVCodecContext* pCodecCtx=NULL; //ffmpeg 解码类的类成员
|
|
|
+
|
|
|
+//AVFormatContext* pFormatCtx=NULL; //保存视频流的信息
|
|
|
+
|
|
|
+//AVFormatContext * fmtctx = avformat_alloc_context();
|
|
|
+
|
|
|
+// fmtctx->oformat= av_guess_format("rtsp",NULL,NULL);
|
|
|
+// snprintf(fmtctx->filename,sizeof(fmtctx->filename),"rtsp://127.0.0.1:9554/te.sdp");
|
|
|
+//// pFormatCtx=avformat_alloc_context();
|
|
|
+//AVDictionary* options=NULL;
|
|
|
+//// av_dict_set(&options,"buffer_size","1024000",0);
|
|
|
+//// av_dict_set(&options,"max_delay","500000",0);
|
|
|
+//av_dict_set(&options,"rtsp_transport","tcp",0);
|
|
|
+//// av_dict_set(&options,"stimeout","2000000",0);//如果没有设置stimeout,那么流地址错误,av_read_frame会阻塞(时间单位是微妙)
|
|
|
+
|
|
|
+//int nrtn = avformat_init_output(fmtctx,&options);
|
|
|
+
|
|
|
+
|
|
|
+int openOutputFile()
|
|
|
+{
|
|
|
+ av_register_all(); //注册库中所有的文件格式和编码器
|
|
|
+ avformat_network_init();
|
|
|
+
|
|
|
+ avcodec_register_all();
|
|
|
+
|
|
|
+
|
|
|
+ const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
|
|
|
+ AVCodecContext *c= NULL;
|
|
|
+
|
|
|
+ c = avcodec_alloc_context3(codec);
|
|
|
+
|
|
|
+ if(c == NULL)std::cout<<"c NULL ."<<std::endl;
|
|
|
+// pkt = av_packet_alloc();
|
|
|
+// if (!pkt)
|
|
|
+// exit(1);
|
|
|
+ c->bit_rate = 4000000;
|
|
|
+
|
|
|
+ c->width = 1280;
|
|
|
+ c->height = 720;
|
|
|
+
|
|
|
+ c->time_base = (AVRational){1, 30};
|
|
|
+ c->framerate = (AVRational){30, 1};
|
|
|
+
|
|
|
+ c->gop_size = 10;
|
|
|
+ c->max_b_frames = 1;
|
|
|
+ c->pix_fmt = AV_PIX_FMT_NV12;// AV_PIX_FMT_YUV420P;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (codec->id == AV_CODEC_ID_H264)
|
|
|
+ {
|
|
|
+ av_opt_set(c->priv_data, "profile", "baseline", 0);
|
|
|
+
|
|
|
+
|
|
|
+ av_opt_set(c->priv_data, "preset", "fast", 0);
|
|
|
+ av_opt_set(c->priv_data, "tune", "zerolatency", 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ int retc = avcodec_open2(c, codec, NULL);
|
|
|
+ if (retc < 0) {
|
|
|
+ std::cout<<"Could not open codec: "<<std::endl;
|
|
|
+// fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
|
|
|
+ exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ AVFormatContext * fmtctx = NULL;
|
|
|
+ int nrtn = avformat_alloc_output_context2(&fmtctx,NULL,"rtsp","rtsp://127.0.0.1:9554/test2.sdp");
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ fmtctx->bit_rate = 2000000;
|
|
|
+ fmtctx->fps_probe_size = 30;
|
|
|
+
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ AVStream *out_stream = avformat_new_stream(fmtctx, codec);
|
|
|
+
|
|
|
+ out_stream->codecpar->bit_rate = 2000000;
|
|
|
+ out_stream->codecpar->width = 1280;
|
|
|
+ out_stream->codecpar->height = 720;
|
|
|
+
|
|
|
+
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ av_dump_format(fmtctx, 0, fmtctx->filename, 1);
|
|
|
+
|
|
|
+// int nrx = avformat_init_output(fmtctx,NULL);
|
|
|
+
|
|
|
+ ret = avio_open(&fmtctx->pb,fmtctx->filename,AVIO_FLAG_WRITE);
|
|
|
+// fmtctx->flags |= AVFMT_FLAG_NONBLOCK;
|
|
|
+// if (!(fmtctx->flags & AVFMT_NOFILE)) {
|
|
|
+//// AVIOInterruptCB ioCb = { &FfmpegMuxer::ioInterruptCallback, this };
|
|
|
+// ret = avio_open2(&fmtctx->pb, m_outputFilename.c_str(), AVIO_FLAG_WRITE, &ioCb, nullptr);
|
|
|
+// if (ret < 0) {
|
|
|
+// err = ERROR_CODE_FFMPEG_OPEN_AVIO_FAILED;
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ std::cout<<"ret: "<<ret<<std::endl;
|
|
|
+ AVDictionary* options = nullptr;
|
|
|
+ av_dict_set(&options, "rtsp_transport", "tcp", 0);
|
|
|
+ av_dict_set(&options, "stimeout", "8000000", 0);
|
|
|
+ ret = avformat_write_header(fmtctx, &options);
|
|
|
+ if (options != nullptr) {
|
|
|
+ av_dict_free(&options);
|
|
|
+ }
|
|
|
+ if (ret < 0) {
|
|
|
+ err = -1;
|
|
|
+ }
|
|
|
+// } while (0);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int test2()
|
|
|
+{
|
|
|
+ AVFormatContext *pFormatCtx;
|
|
|
+ AVCodecContext *pCodecCtx;
|
|
|
+ AVCodec *pCodec;
|
|
|
+ AVFrame *pFrame, *pFrameRGB;
|
|
|
+ AVPacket *packet;
|
|
|
+ uint8_t *out_buffer;
|
|
|
+
|
|
|
+ static struct SwsContext *img_convert_ctx;
|
|
|
+
|
|
|
+ int videoStream, i, numBytes;
|
|
|
+ int ret, got_picture;
|
|
|
+
|
|
|
+ avformat_network_init(); ///初始化FFmpeg网络模块,2017.8.5---lizhen
|
|
|
+ av_register_all(); //初始化FFMPEG 调用了这个才能正常适用编码器和解码器
|
|
|
+
|
|
|
+
|
|
|
+ //Allocate an AVFormatContext.
|
|
|
+ pFormatCtx = avformat_alloc_context();
|
|
|
+
|
|
|
+ ///2017.8.5---lizhen
|
|
|
+ AVDictionary *avdic=NULL;
|
|
|
+ char option_key[]="rtsp_transport";
|
|
|
+ char option_value[]="tcp";
|
|
|
+ av_dict_set(&avdic,option_key,option_value,0);
|
|
|
+// char option_key2[]="max_delay";
|
|
|
+// char option_value2[]="100";
|
|
|
+// av_dict_set(&avdic,option_key2,option_value2,0);
|
|
|
+ ///rtsp地址,可根据实际情况修改
|
|
|
+ char url[]="rtsp://111.33.136.149:9554/test2.sdp";
|
|
|
+
|
|
|
+
|
|
|
+ if (avformat_open_input(&pFormatCtx, url, NULL, &avdic) != 0) {
|
|
|
+ printf("can't open the file. \n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
|
|
|
+ printf("Could't find stream infomation.\n");
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#include "ffmpeg_outputer.h"
|
|
|
+
|
|
|
+
|
|
|
+#include "modulecomm.h"
|
|
|
+
|
|
|
+
|
|
|
+std::shared_ptr<char> gpstr_data;
|
|
|
+bool gbUpdate = false;
|
|
|
+int gndatasize;
|
|
|
+std::mutex gmutex;
|
|
|
+
|
|
|
+void Listenframe(const char * strdata,const unsigned int nSize,const unsigned int index,const QDateTime * dt,const char * strmemname)
|
|
|
+{
|
|
|
+ if(nSize<10)return;
|
|
|
+ std::shared_ptr<char> pstr = std::shared_ptr<char>(new char[nSize]);
|
|
|
+ memcpy(pstr.get(),strdata,nSize);
|
|
|
+ gmutex.lock();
|
|
|
+ gpstr_data = pstr;
|
|
|
+ gndatasize = nSize;
|
|
|
+ gbUpdate = true;
|
|
|
+ gmutex.unlock();
|
|
|
+// qDebug(" %02x %02x %02x %02x %02x %02x",strdata[0],strdata[1],strdata[2],strdata[3],strdata[4],strdata[5]);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+std::mutex gmutexlat;
|
|
|
+namespace iv {
|
|
|
+struct datapac
|
|
|
+{
|
|
|
+ int64_t sendtime;
|
|
|
+ int nsize;
|
|
|
+};
|
|
|
+}
|
|
|
+std::vector<iv::datapac> gvectorsend;
|
|
|
+
|
|
|
+void threadrecv()
|
|
|
+{
|
|
|
+ static AVFormatContext *i_fmt_ctx;
|
|
|
+ static AVStream *i_video_stream;
|
|
|
+
|
|
|
+ static AVFormatContext *o_fmt_ctx;
|
|
|
+ static AVStream *o_video_stream;
|
|
|
+
|
|
|
+ static bool bStop = false;
|
|
|
+ static int frame_nums = 0;
|
|
|
+
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
|
+
|
|
|
+ /* should set to NULL so that avformat_open_input() allocate a new one */
|
|
|
+ i_fmt_ctx = NULL;
|
|
|
+ //这是我用ONVIF协议得到的摄像头RTSP流媒体地址
|
|
|
+ char rtspUrl[] = "rtsp://111.33.136.149:9554/mystream";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (avformat_open_input(&i_fmt_ctx, rtspUrl, NULL, NULL)!=0)
|
|
|
+ {
|
|
|
+ fprintf(stderr, " = could not open input file\n");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ AVDictionary *opts = NULL;
|
|
|
+
|
|
|
+ av_dict_set(&opts, "rtsp_transport", "tcp", 0);
|
|
|
+// av_dict_set(&opts, "muxdelay", "0.1", 0);
|
|
|
+
|
|
|
+
|
|
|
+ if (avformat_find_stream_info(i_fmt_ctx, &opts)<0)
|
|
|
+ {
|
|
|
+ fprintf(stderr, " = could not find stream info\n");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ int last_pts = 0;
|
|
|
+ int last_dts = 0;
|
|
|
+
|
|
|
+ int64_t pts, dts;
|
|
|
+ while(!bStop)
|
|
|
+ {
|
|
|
+ //printf("------------------------------------------------------\n");
|
|
|
+ AVPacket i_pkt;
|
|
|
+ av_init_packet(&i_pkt);
|
|
|
+ i_pkt.size = 0;
|
|
|
+ i_pkt.data = NULL;
|
|
|
+ if (av_read_frame(i_fmt_ctx, &i_pkt) <0 )
|
|
|
+ break;
|
|
|
+
|
|
|
+ int sizedata = i_pkt.size;
|
|
|
+ int i;;
|
|
|
+ gmutexlat.lock();
|
|
|
+ for(i=gvectorsend.size();i>=0;i--)
|
|
|
+ {
|
|
|
+ iv::datapac xpac = gvectorsend[i];
|
|
|
+ if(xpac.nsize == i_pkt.size)
|
|
|
+ {
|
|
|
+ std::cout<<"Latency: "<<(std::chrono::system_clock::now().time_since_epoch().count()/1000000 - xpac.sendtime)<<std::endl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ gmutexlat.unlock();
|
|
|
+ std::cout<<" time: "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<" read packet size:"<<i_pkt.size<<std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ QCoreApplication a(argc, argv);
|
|
|
+
|
|
|
+ void * pa = iv::modulecomm::RegisterRecv("h264front",Listenframe);
|
|
|
+ AVFormatContext *ifmt_ctx = NULL;
|
|
|
+ AVPacket pkt;
|
|
|
+ const char *in_filename, *out_filename;
|
|
|
+ FfmpegOutputer *pusher = NULL;
|
|
|
+ int ret;
|
|
|
+ int frame_index = 0;
|
|
|
+
|
|
|
+ in_filename = "/home/yuchuli/imx291.h264";
|
|
|
+
|
|
|
+ out_filename = "rtsp://111.33.136.149:9554/testhello2";
|
|
|
+ //out_filename = "rtp://233.233.233.233:6666";
|
|
|
+ //out_filename = "tcp://127.0.0.1:9000";
|
|
|
+ //out_filename = "udp://127.0.0.1:9000";
|
|
|
+
|
|
|
+ av_register_all(); //初始化FFMPEG 调用了这个才能正常适用编码器和解码器
|
|
|
+
|
|
|
+ //Network
|
|
|
+ avformat_network_init();
|
|
|
+
|
|
|
+
|
|
|
+ std::thread * precvthread = new std::thread(threadrecv);
|
|
|
+
|
|
|
+ if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
|
|
|
+ printf("Could not open input file.");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
|
|
|
+ printf("Failed to retrieve input stream information");
|
|
|
+ return -2 ;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ ifmt_ctx->streams[0]->avg_frame_rate.num = 30;
|
|
|
+ ifmt_ctx->streams[0]->codecpar->sample_aspect_ratio.num = 30;
|
|
|
+ ifmt_ctx->streams[0]->time_base.den = 30;
|
|
|
+
|
|
|
+ ifmt_ctx->bit_rate = 2000000;
|
|
|
+ if (NULL == pusher) {
|
|
|
+ pusher = new FfmpegOutputer();
|
|
|
+ ret = pusher->OpenOutputStream(out_filename, ifmt_ctx);
|
|
|
+ if (ret != 0){
|
|
|
+ return -3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ av_dump_format(ifmt_ctx, 0, in_filename, 0);
|
|
|
+
|
|
|
+ int pos = 0;
|
|
|
+ av_read_frame(ifmt_ctx, &pkt);
|
|
|
+ while (true) {
|
|
|
+
|
|
|
+ if(gbUpdate == false)
|
|
|
+ {
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
|
+// av_usleep(1000);
|
|
|
+ // std::cout<<"sleep. "<<std::endl;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // continue;
|
|
|
+ gmutex.lock();
|
|
|
+
|
|
|
+ pkt.buf = NULL;
|
|
|
+ pkt.duration = 0;
|
|
|
+ pkt.data = new unsigned char[gndatasize];
|
|
|
+ // pkt.buf->data = pkt.data;
|
|
|
+ memcpy(pkt.data, gpstr_data.get(),gndatasize);
|
|
|
+ pkt.size = gndatasize;
|
|
|
+ // std::cout<<" size : "<<gndatasize<<std::endl;
|
|
|
+ // std::cout<<" buf size: "<<pkt.buf->size<<std::endl;
|
|
|
+ // pkt.buf->size = gndatasize;
|
|
|
+ pkt.pos = pos;
|
|
|
+ pkt.pts = AV_NOPTS_VALUE;
|
|
|
+ pkt.dts = AV_NOPTS_VALUE;
|
|
|
+ pos = pos + gndatasize;
|
|
|
+ gbUpdate = false;
|
|
|
+ gmutex.unlock();
|
|
|
+ pkt.flags = 0;
|
|
|
+
|
|
|
+ iv::datapac xpac;
|
|
|
+ xpac.nsize = pkt.size;
|
|
|
+ xpac.sendtime = std::chrono::system_clock::now().time_since_epoch().count()/1000000;
|
|
|
+ // std::cout<<"send frame "<<std::endl;
|
|
|
+ // ret = av_read_frame(ifmt_ctx, &pkt);
|
|
|
+ gmutexlat.lock();
|
|
|
+ gvectorsend.push_back(xpac);
|
|
|
+ while(gvectorsend.size()>100)gvectorsend.erase(gvectorsend.begin());
|
|
|
+ gmutexlat.unlock();
|
|
|
+ std::cout<<" time: "<<std::chrono::system_clock::now().time_since_epoch().count()/1000000<<" pos: "<<pkt.pos<<" size: "<<pkt.size<<" flats: "<<pkt.flags<< std::endl;
|
|
|
+ // if (ret < 0) break;
|
|
|
+
|
|
|
+ pkt.duration = 3;
|
|
|
+
|
|
|
+// std::cout<<" pts: "<<pkt.pts<<" dts: "<<pkt.dts<<std::endl;
|
|
|
+ if (pkt.pts == AV_NOPTS_VALUE) {
|
|
|
+ pkt.dts = pkt.pts = (1.0/30)*90*frame_index;
|
|
|
+ // pkt.dts = pkt.pts = frame_index * 1;
|
|
|
+ // frame_index++;
|
|
|
+
|
|
|
+ }
|
|
|
+ // std::cout<<" pts: "<<pkt.pts<<" dts: "<<pkt.dts<<std::endl;
|
|
|
+
|
|
|
+ pusher->InputPacket(&pkt);
|
|
|
+ av_packet_unref(&pkt);
|
|
|
+// delete pkt.data;
|
|
|
+ frame_index++;
|
|
|
+// av_usleep(40000);
|
|
|
+ }
|
|
|
+
|
|
|
+ end:
|
|
|
+ avformat_close_input(&ifmt_ctx);
|
|
|
+ avformat_free_context(ifmt_ctx);
|
|
|
+ delete pusher;
|
|
|
+
|
|
|
+
|
|
|
+ // test2();
|
|
|
+// openOutputFile();
|
|
|
+// avcodec_register_all();
|
|
|
+// avformat_network_init();
|
|
|
+
|
|
|
+// char* video_dir="rtsp://admin:yltx8888@192.168.37.210:554/h264/ch1/main/av_stream";
|
|
|
+// char* video_dir="rtmp://58.200.131.2:1935/livetv/cctv6";
|
|
|
+
|
|
|
+
|
|
|
+// AVFormatContext * fmtctx = avformat_alloc_context();
|
|
|
+// fmtctx->oformat= av_guess_format("rtsp",NULL,NULL);
|
|
|
+// snprintf(fmtctx->filename,sizeof(fmtctx->filename),"rtsp://127.0.0.1:9554/te.sdp");
|
|
|
+// int nrtn = avio_open(&fmtctx->pb,fmtctx->filename,AVIO_FLAG_WRITE);
|
|
|
+// std::cout<<"hello "<<std::endl;
|
|
|
+//// int nrtn = avformat_open_input(&fmtctx,fmtctx->filename,NULL,NULL);
|
|
|
+// std::cout<<" nrtn : "<<nrtn<<std::endl;
|
|
|
+ return a.exec();
|
|
|
+}
|
|
|
+
|
|
|
+
|