Ticket #7472: main.cpp

File main.cpp, 8.3 KB (added by andreanobile, 6 years ago)

source code of program

Line 
1
2extern "C" {
3#include <libavutil/opt.h>
4#include <libavcodec/avcodec.h>
5#include <libavutil/channel_layout.h>
6#include <libavutil/common.h>
7#include <libavutil/imgutils.h>
8#include <libavutil/mathematics.h>
9#include <libavutil/samplefmt.h>
10
11#include <libavformat/avformat.h>
12#include <libavcodec/avcodec.h>
13#include <libavutil/imgutils.h>
14#include <libswscale/swscale.h>
15}
16
17#include <string>
18
19#include <opencv2/opencv.hpp>
20
21using namespace std;
22using namespace cv;
23
24
25
26int write_frame_(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
27{
28 /* rescale output packet timestamp values from codec to stream timebase */
29 pkt->pts = av_rescale_q_rnd(pkt->pts, *time_base, st->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
30 pkt->dts = av_rescale_q_rnd(pkt->dts, *time_base, st->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
31 pkt->duration = av_rescale_q(pkt->duration, *time_base, st->time_base);
32 pkt->stream_index = st->index;
33
34 /* Write the compressed frame to the media file. */
35 return av_interleaved_write_frame(fmt_ctx, pkt);
36}
37
38
39void initialize_avformat_context(AVFormatContext **fctx, const char *format_name)
40{
41 int ret = avformat_alloc_output_context2(fctx, nullptr, format_name, nullptr);
42 if (ret < 0)
43 {
44 std::cout << "Could not allocate output format context!" << std::endl;
45 exit(1);
46 }
47}
48
49
50int initialize_io_context(AVFormatContext *fctx, const char *output)
51{
52 int ret = 0;
53 if (!(fctx->oformat->flags & AVFMT_NOFILE)) {
54 ret = avio_open2(&fctx->pb, output, AVIO_FLAG_WRITE, nullptr, nullptr);
55 if (ret < 0) {
56 std::cout << "Could not open output IO context!" << std::endl;
57 return ret;
58 }
59 }
60 return ret;
61}
62
63
64void set_codec_params(AVFormatContext *fctx, AVCodecContext *codec_ctx, double width, double height, int fps, int bitrate)
65{
66 const AVRational dst_fps = {fps, 1};
67
68 codec_ctx->codec_tag = 0;
69 codec_ctx->codec_id = AV_CODEC_ID_H264;
70 codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
71 codec_ctx->width = width;
72 codec_ctx->height = height;
73 codec_ctx->gop_size = 12;
74 codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
75 codec_ctx->framerate = dst_fps;
76 codec_ctx->time_base = av_inv_q(dst_fps);
77 codec_ctx->bit_rate = bitrate;
78 if (fctx->oformat->flags & AVFMT_GLOBALHEADER)
79 {
80 codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
81 }
82}
83
84
85void initialize_codec_stream(AVStream *stream, AVCodecContext *codec_ctx, AVCodec *codec, std::string codec_profile)
86{
87 int ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
88 if (ret < 0)
89 {
90 std::cout << "Could not initialize stream codec parameters!" << std::endl;
91 exit(1);
92 }
93
94 AVDictionary *codec_options = nullptr;
95 av_dict_set(&codec_options, "profile", codec_profile.c_str(), 0);
96 av_dict_set(&codec_options, "preset", "superfast", 0);
97 av_dict_set(&codec_options, "tune", "zerolatency", 0);
98
99 // open video encoder
100 ret = avcodec_open2(codec_ctx, codec, &codec_options);
101 if (ret < 0)
102 {
103 std::cout << "Could not open video encoder!" << std::endl;
104 exit(1);
105 }
106}
107
108
109SwsContext *initialize_sample_scaler(AVCodecContext *codec_ctx, int width, int height)
110{
111 SwsContext *swsctx = sws_getContext(width, height, AV_PIX_FMT_BGR24, width, height, codec_ctx->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr);
112 if (!swsctx)
113 {
114 std::cout << "Could not initialize sample scaler!" << std::endl;
115 exit(1);
116 }
117
118 return swsctx;
119}
120
121
122AVFrame *set_frame_buffer(AVCodecContext *codec_ctx, int width, int height, std::vector<uint8_t> &framebuf)
123{
124 AVFrame *frame = av_frame_alloc();
125
126 av_image_fill_arrays(frame->data, frame->linesize, framebuf.data(), codec_ctx->pix_fmt, width, height, 1);
127
128 frame->width = width;
129 frame->height = height;
130 frame->format = static_cast<int>(codec_ctx->pix_fmt);
131
132 return frame;
133}
134
135
136void write_frame(AVCodecContext *codec_ctx, AVFormatContext *fmt_ctx, AVFrame *frame)
137{
138 AVPacket pkt = {0};
139 av_init_packet(&pkt);
140
141 int ret = avcodec_send_frame(codec_ctx, frame);
142 if (ret < 0)
143 {
144 std::cout << "Error sending frame to codec context!" << std::endl;
145 exit(1);
146 }
147
148 ret = avcodec_receive_packet(codec_ctx, &pkt);
149 if (ret < 0)
150 {
151 std::cout << "Error receiving packet from codec context!" << std::endl;
152 exit(1);
153 }
154
155 av_interleaved_write_frame(fmt_ctx, &pkt);
156 av_packet_unref(&pkt);
157}
158
159
160class Streamer
161{
162 AVFormatContext *ofmt_ctx;
163 AVCodec *out_codec;
164 AVStream *out_stream;
165 AVCodecContext *out_codec_ctx;
166 AVFrame *frame;
167 SwsContext *swsctx;
168 std::vector<uint8_t> framebuf;
169 bool init_failure;
170
171public:
172 Streamer();
173 ~Streamer();
174
175 void write_video_frame(cv::Mat &image, int play);
176 void put_frame(cv::Mat &image);
177
178 void stream_init(int width, int height, int fps, int bitrate, const std::string &codec_profile, const std::string &server);
179
180
181};
182
183
184
185void Streamer::put_frame(cv::Mat &image)
186{
187 if (init_failure) {
188 return;
189 }
190
191 const int stride[] = {static_cast<int>(image.step[0])};
192 sws_scale(swsctx, &image.data, stride, 0, image.rows, frame->data, frame->linesize);
193
194 frame->pts += av_rescale_q(1, out_codec_ctx->time_base, out_stream->time_base);
195
196 write_frame(out_codec_ctx, ofmt_ctx, frame);
197}
198
199
200void Streamer::stream_init(int width, int height, int fps, int bitrate, const std::string &codec_profile, const std::string &server)
201{
202
203 av_log_set_level(AV_LOG_DEBUG);
204
205 printf("init network\n");
206 avformat_network_init();
207
208 int ret;
209
210
211 initialize_avformat_context(&ofmt_ctx, "flv");
212
213 int init = 1;
214 init = initialize_io_context(ofmt_ctx, server.c_str());
215 if (init != 0) { // failure to initialize
216 init_failure = true;
217 exit(1);
218 return;
219 }
220
221
222 out_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
223 out_stream = avformat_new_stream(ofmt_ctx, out_codec);
224 out_codec_ctx = avcodec_alloc_context3(out_codec);
225
226 set_codec_params(ofmt_ctx, out_codec_ctx, width, height, fps, bitrate);
227 initialize_codec_stream(out_stream, out_codec_ctx, out_codec, codec_profile);
228
229 out_stream->codecpar->extradata = out_codec_ctx->extradata;
230 out_stream->codecpar->extradata_size = out_codec_ctx->extradata_size;
231
232 av_dump_format(ofmt_ctx, 0, server.c_str(), 1);
233
234 swsctx = initialize_sample_scaler(out_codec_ctx, width, height);
235 framebuf.resize(av_image_get_buffer_size(out_codec_ctx->pix_fmt, width, height, 1));
236 frame = set_frame_buffer(out_codec_ctx, width, height, framebuf);
237
238 ret = avformat_write_header(ofmt_ctx, nullptr);
239 if (ret < 0)
240 {
241 std::cout << "Could not write header!" << std::endl;
242 exit(1);
243 }
244}
245
246
247
248Streamer::Streamer()
249{
250 ofmt_ctx = nullptr;
251 out_codec = nullptr;
252 out_stream = nullptr;
253 out_codec_ctx = nullptr;
254 frame = nullptr;
255 swsctx = nullptr;
256 init_failure = false;
257
258#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
259 av_register_all();
260#endif
261}
262
263
264Streamer::~Streamer()
265{
266 if(ofmt_ctx) av_write_trailer(ofmt_ctx);
267 if(frame) {
268 av_frame_free(&frame);
269 frame = nullptr;
270 }
271
272
273 if(ofmt_ctx) {
274 avio_close(ofmt_ctx->pb);
275 avformat_free_context(ofmt_ctx);
276 ofmt_ctx = nullptr;
277 }
278
279 if(out_codec_ctx) {
280 avcodec_close(out_codec_ctx); //double free
281 out_codec_ctx = nullptr;
282 }
283
284}
285
286
287int main(int argc, char *argv[])
288{
289 std::string video_fname;
290 video_fname = std::string(argv[1]);
291
292 Streamer streamer;
293
294 VideoCapture video_capture(video_fname, CAP_FFMPEG);
295 if(!video_capture.isOpened()) {
296 CV_Error(cv::Error::StsBadArg, "could not open video path/file \n");
297 return 1;
298 }
299
300 int cap_frame_width = video_capture.get(CAP_PROP_FRAME_WIDTH);
301 int cap_frame_height = video_capture.get(CAP_PROP_FRAME_HEIGHT);
302
303 int cap_fps = video_capture.get(CAP_PROP_FPS);
304 printf("video info w = %d, h = %d, fps = %d\n", cap_frame_width, cap_frame_height, cap_fps);
305
306 int bitrate = 1000000;
307
308 streamer.stream_init(cap_frame_width, cap_frame_height, cap_fps, bitrate,
309 "high444", "rtmp://localhost/live/mystream");
310
311 Mat frame;
312 bool ok = video_capture.read(frame);
313 while(ok) {
314 streamer.put_frame(frame);
315 ok = video_capture.read(frame);
316 }
317 video_capture.release();
318
319 return 0;
320}
321