Commit 09a835c9a88bd9eb4e1f39bb9f09e164c4a3b7bc
1 parent
7b1de685
修正视频截存丢帧问题
Showing
8 changed files
with
159 additions
and
635 deletions
src/decoder/dvpp/FFRecoder.cpp
1 | +// FFRecoder.cpp | |
1 | 2 | #include "FFRecoder.h" |
2 | - | |
3 | 3 | #include <tuple> |
4 | 4 | #include <array> |
5 | 5 | #include <vector> |
6 | 6 | |
7 | +extern "C" { | |
8 | +#include <libavcodec/avcodec.h> | |
9 | +#include <libavformat/avformat.h> | |
10 | +#include <libavutil/opt.h> | |
11 | +#include <libavutil/timestamp.h> | |
12 | +#include <libavutil/imgutils.h> | |
13 | +#include <libswscale/swscale.h> | |
14 | +} | |
15 | + | |
7 | 16 | |
8 | 17 | FFRecoder::FFRecoder() |
9 | 18 | :width_{}, |
... | ... | @@ -14,20 +23,17 @@ FFRecoder::FFRecoder() |
14 | 23 | codec_ctx_{ nullptr }, |
15 | 24 | fmt_ctx_{ nullptr }, |
16 | 25 | out_stream_{ nullptr }, |
17 | - yuv_frame_{ nullptr }, | |
18 | - img_convert_ctx{nullptr} | |
26 | + yuv_frame_{ nullptr } | |
19 | 27 | { |
20 | - bFirstFrame = true; | |
21 | - last_src_pts = 0; | |
22 | - last_pts = 0; | |
23 | 28 | } |
24 | 29 | |
25 | 30 | FFRecoder::~FFRecoder() |
26 | 31 | { |
32 | + uninit(); | |
27 | 33 | } |
28 | 34 | |
29 | 35 | |
30 | -bool FFRecoder::init(int w, int h, AVRational time_base, AVCodecContext* avctx, const char* outfile_name) | |
36 | +bool FFRecoder::init(int w, int h, int fps, int bit_rate, const char* outfile_name) | |
31 | 37 | { |
32 | 38 | uninit(); |
33 | 39 | |
... | ... | @@ -36,30 +42,32 @@ bool FFRecoder::init(int w, int h, AVRational time_base, AVCodecContext* avctx, |
36 | 42 | y_size_ = w * h; |
37 | 43 | uv_size_ = y_size_ / 4; |
38 | 44 | |
45 | + m_fps = fps; | |
46 | + | |
39 | 47 | // [1] 创建解码器 |
40 | - const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_HEVC); | |
48 | + const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_H264); | |
41 | 49 | if (!encoder) { |
42 | - LOG_ERROR("Find encoder AV_CODEC_ID_H264 failed!"); | |
50 | + fprintf(stderr, "Find encoder AV_CODEC_ID_H264 failed!\n"); | |
43 | 51 | return false; |
44 | 52 | } |
45 | 53 | // 获取解码器上下文 |
46 | 54 | codec_ctx_ = avcodec_alloc_context3(encoder); |
47 | 55 | if (!codec_ctx_) { |
48 | - LOG_ERROR("Alloc context for encoder contx failed!"); | |
56 | + fprintf(stderr, "Alloc context for encoder contx failed!\n"); | |
49 | 57 | return false; |
50 | 58 | } |
51 | 59 | // 设置解码器上下文参数 |
52 | - codec_ctx_->bit_rate = avctx->bit_rate; | |
60 | + codec_ctx_->bit_rate = bit_rate; | |
53 | 61 | codec_ctx_->width = width_; |
54 | 62 | codec_ctx_->height = height_; |
55 | - codec_ctx_->time_base = time_base; | |
56 | - codec_ctx_->gop_size = avctx->gop_size; | |
57 | - codec_ctx_->max_b_frames = avctx->max_b_frames; | |
63 | + codec_ctx_->time_base = AVRational{ 1, fps }; | |
64 | + codec_ctx_->gop_size = 50; | |
65 | + codec_ctx_->max_b_frames = 0; | |
58 | 66 | codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P; |
59 | 67 | codec_ctx_->thread_count = 4; |
60 | - codec_ctx_->qmin = avctx->qmin; | |
61 | - codec_ctx_->qmax = avctx->qmax; | |
62 | - codec_ctx_->qcompress = avctx->qcompress; | |
68 | + codec_ctx_->qmin = 10; | |
69 | + codec_ctx_->qmax = 51; | |
70 | + codec_ctx_->qcompress = 0.6f; | |
63 | 71 | codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
64 | 72 | |
65 | 73 | av_opt_set(codec_ctx_->priv_data, "preset", "ultrafast", 0); |
... | ... | @@ -68,7 +76,7 @@ bool FFRecoder::init(int w, int h, AVRational time_base, AVCodecContext* avctx, |
68 | 76 | // 打开解码器 |
69 | 77 | int ret = avcodec_open2(codec_ctx_, encoder, nullptr); |
70 | 78 | if (ret < 0) { |
71 | - LOG_ERROR("Open encoder failed!"); | |
79 | + fprintf(stderr, "Open encoder failed!\n"); | |
72 | 80 | return false; |
73 | 81 | } |
74 | 82 | |
... | ... | @@ -80,7 +88,6 @@ bool FFRecoder::init(int w, int h, AVRational time_base, AVCodecContext* avctx, |
80 | 88 | out_stream_->id = 0; |
81 | 89 | out_stream_->codecpar->codec_tag = 0; |
82 | 90 | avcodec_parameters_from_context(out_stream_->codecpar, codec_ctx_); |
83 | - out_stream_->time_base = { 1,30 }; | |
84 | 91 | |
85 | 92 | av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); |
86 | 93 | |
... | ... | @@ -93,113 +100,25 @@ bool FFRecoder::init(int w, int h, AVRational time_base, AVCodecContext* avctx, |
93 | 100 | if (av_frame_get_buffer(yuv_frame_, 0) < 0) { |
94 | 101 | av_frame_free(&yuv_frame_); |
95 | 102 | yuv_frame_ = nullptr; |
96 | - LOG_ERROR("Frame get buffer failed!"); | |
97 | - return false; | |
98 | - } | |
99 | - | |
100 | - // [5] 打开输出视频文件并写入视频头信息 | |
101 | - if (avio_open(&fmt_ctx_->pb, outfile_name, AVIO_FLAG_WRITE) < 0) { | |
102 | - LOG_ERROR("avio_open failed!"); | |
103 | - return false; | |
104 | - } | |
105 | - if (avformat_write_header(fmt_ctx_, nullptr) < 0) { | |
106 | - LOG_ERROR("Write header failed!"); | |
107 | - return false; | |
108 | - } | |
109 | - | |
110 | - // 计算解码后原始数据所需缓冲区大小,并分配内存空间 Determine required buffer size and allocate buffer | |
111 | - int numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, w, h, 1); | |
112 | - out_buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t)); | |
113 | - | |
114 | - //pFrameOut = av_frame_alloc(); | |
115 | - //av_image_fill_arrays(pFrameOut->data, pFrameOut->linesize, buffer, AV_PIX_FMT_YUV420P, w, h, 1); | |
116 | - | |
117 | - img_convert_ctx = sws_getContext(avctx->width, avctx->height, avctx->pix_fmt, w, h, AV_PIX_FMT_YUV420P, | |
118 | - SWS_BICUBIC, nullptr, nullptr, nullptr); | |
119 | - | |
120 | - return true; | |
121 | -} | |
122 | - | |
123 | -bool FFRecoder::init(AVStream* stream, AVCodecContext* avctx, const char* outfile_name) { | |
124 | - | |
125 | - const AVCodec* encoder = avcodec_find_encoder(avctx->codec_id); | |
126 | - if (!encoder) { | |
127 | - LOG_ERROR("Find encoder AV_CODEC_ID_H264 failed!"); | |
128 | - return false; | |
129 | - } | |
130 | - // 获取解码器上下文 | |
131 | - codec_ctx_ = avcodec_alloc_context3(encoder); | |
132 | - if (!codec_ctx_) { | |
133 | - LOG_ERROR("Alloc context for encoder contx failed!"); | |
103 | + fprintf(stderr, "Frame get buffer failed!\n"); | |
134 | 104 | return false; |
135 | 105 | } |
136 | 106 | |
137 | - avcodec_copy_context(codec_ctx_, avctx); | |
138 | - codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
139 | - m_inStream = stream; | |
140 | - | |
141 | - // [2] 创建输出上下文 | |
142 | - avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name); | |
143 | - | |
144 | - // [3] 添加输出视频流 | |
145 | - out_stream_ = avformat_new_stream(fmt_ctx_, nullptr); | |
146 | - | |
147 | - out_stream_->id = 0; | |
148 | - out_stream_->codecpar->codec_tag = 0; | |
149 | - avcodec_parameters_from_context(out_stream_->codecpar, codec_ctx_); | |
150 | - // out_stream_->time_base = { 1,25 }; | |
151 | - out_stream_->time_base = stream->time_base; | |
152 | - out_stream_->r_frame_rate = stream->r_frame_rate; | |
153 | - out_stream_->avg_frame_rate = stream->r_frame_rate; | |
154 | - | |
155 | - codec_ctx_->time_base = out_stream_->time_base; | |
156 | - | |
157 | - av_opt_set(out_stream_->codec->priv_data, "preset", "ultrafast", 0); | |
158 | - av_opt_set(out_stream_->codec->priv_data, "tune", "zerolatency", 0); | |
159 | - | |
160 | - // av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); | |
161 | - | |
162 | 107 | // [5] 打开输出视频文件并写入视频头信息 |
163 | 108 | if (avio_open(&fmt_ctx_->pb, outfile_name, AVIO_FLAG_WRITE) < 0) { |
164 | - LOG_ERROR("avio_open failed!"); | |
109 | + fprintf(stderr, "avio_open failed!\n"); | |
165 | 110 | return false; |
166 | 111 | } |
167 | 112 | if (avformat_write_header(fmt_ctx_, nullptr) < 0) { |
168 | - LOG_ERROR("Write header failed!"); | |
113 | + fprintf(stderr, "Write header failed!\n"); | |
169 | 114 | return false; |
170 | 115 | } |
171 | 116 | |
172 | 117 | return true; |
173 | 118 | } |
174 | 119 | |
175 | -void FFRecoder::release() { | |
176 | - av_write_trailer(fmt_ctx_); | |
177 | - | |
178 | - avcodec_close(fmt_ctx_->streams[0]->codec); | |
179 | - av_freep(&fmt_ctx_->streams[0]->codec); | |
180 | - av_freep(&fmt_ctx_->streams[0]); | |
181 | - | |
182 | - avio_close(fmt_ctx_->pb); | |
183 | - av_free(fmt_ctx_); | |
184 | - fmt_ctx_ = nullptr; | |
185 | -} | |
186 | - | |
187 | 120 | void FFRecoder::uninit() |
188 | 121 | { |
189 | - //if (out_buffer) { | |
190 | - // av_free(out_buffer); | |
191 | - //} | |
192 | - | |
193 | - if (yuv_frame_) { | |
194 | - av_frame_free(&yuv_frame_); | |
195 | - yuv_frame_ = nullptr; | |
196 | - } | |
197 | - | |
198 | - if (img_convert_ctx) { | |
199 | - sws_freeContext(img_convert_ctx); | |
200 | - img_convert_ctx = nullptr; | |
201 | - } | |
202 | - | |
203 | 122 | if (fmt_ctx_) { |
204 | 123 | av_write_trailer(fmt_ctx_); |
205 | 124 | avio_close(fmt_ctx_->pb); |
... | ... | @@ -213,6 +132,11 @@ void FFRecoder::uninit() |
213 | 132 | codec_ctx_ = nullptr; |
214 | 133 | } |
215 | 134 | |
135 | + if (yuv_frame_) { | |
136 | + av_frame_free(&yuv_frame_); | |
137 | + yuv_frame_ = nullptr; | |
138 | + } | |
139 | + | |
216 | 140 | width_ = 0; |
217 | 141 | height_ = 0; |
218 | 142 | y_size_ = 0; |
... | ... | @@ -250,84 +174,13 @@ bool FFRecoder::write_yuv(const uint8_t* yuv_data) |
250 | 174 | return write_frame(yuv_frame_); |
251 | 175 | } |
252 | 176 | |
253 | -void FFRecoder::update_pts(AVPacket* pkt) { | |
254 | - if (pkt->pts > 0) { | |
255 | - if (bFirstFrame) { | |
256 | - bFirstFrame = false; | |
257 | - last_src_pts = pkt->pts; | |
258 | - } | |
259 | - int64_t pkt_pts = pkt->pts; | |
260 | - pkt->pts = last_pts + (pkt_pts - last_src_pts); | |
261 | - last_src_pts = pkt_pts; | |
262 | - last_pts = pkt->pts; | |
263 | - pkt->dts = pkt->pts; | |
264 | - } | |
265 | - else { | |
266 | - if (bFirstFrame) { | |
267 | - bFirstFrame = false; | |
268 | - last_pts = 0; | |
269 | - } | |
270 | - pkt->pts = last_pts + 512; | |
271 | - last_pts = pkt->pts; | |
272 | - } | |
273 | - | |
274 | -} | |
275 | - | |
276 | -bool FFRecoder::write_pkt(AVPacket *pkt) { | |
277 | - char errbuf[64]{ 0 }; | |
278 | - | |
279 | - // av_packet_rescale_ts(pkt, codec_ctx_->time_base, out_stream_->time_base); | |
280 | - // update_pts(pkt); | |
281 | - // pkt->stream_index = out_stream_->index; | |
282 | - | |
283 | - if(pkt->pts==AV_NOPTS_VALUE) { | |
284 | - // printf("frame_index:%d", frame_index); | |
285 | - //Write PTS | |
286 | - AVRational time_base1 = codec_ctx_->time_base; | |
287 | - //Duration between 2 frames (us) | |
288 | - int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(m_inStream->r_frame_rate); | |
289 | - //Parameters | |
290 | - pkt->pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE); | |
291 | - pkt->dts = pkt->pts; | |
292 | - pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE); | |
293 | - frame_index++; | |
294 | - } | |
295 | - // Convert PTS/DTS | |
296 | - pkt->pts = av_rescale_q_rnd(pkt->pts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
297 | - pkt->dts = av_rescale_q_rnd(pkt->dts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
298 | - pkt->duration = av_rescale_q(pkt->duration, codec_ctx_->time_base, out_stream_->time_base); | |
299 | - | |
300 | - pkt->pos = -1; | |
301 | - pkt->stream_index = out_stream_->index; | |
302 | - fmt_ctx_->duration += pkt->duration; | |
303 | - | |
304 | - // 将数据写入到输出流 | |
305 | - int ret = av_write_frame(fmt_ctx_, pkt); | |
306 | - if (ret < 0) { | |
307 | - LOG_ERROR("Error while writing output packet: {}", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
308 | - return false; | |
309 | - } | |
310 | - return true; | |
311 | -} | |
312 | - | |
313 | -bool FFRecoder::write_frame(AVFrame* frame) | |
177 | +bool FFRecoder::write_frame(const AVFrame* frame) | |
314 | 178 | { |
315 | - AVFrame *pFrameOut = nullptr; | |
316 | - if (frame != nullptr && frame->format != AV_PIX_FMT_YUV420P) { | |
317 | - pFrameOut = av_frame_clone(frame); | |
318 | - pFrameOut->format = AV_PIX_FMT_YUV420P; | |
319 | - av_image_fill_arrays(pFrameOut->data, pFrameOut->linesize, out_buffer, AV_PIX_FMT_YUV420P, frame->width, frame->height, 1); | |
320 | - sws_scale(img_convert_ctx, (const unsigned char* const*)frame->data, frame->linesize, 0, frame->height, pFrameOut->data, pFrameOut->linesize); | |
321 | - } | |
322 | - else { | |
323 | - pFrameOut = frame; | |
324 | - } | |
325 | 179 | char errbuf[64]{ 0 }; |
326 | 180 | // 将帧数据发送到编码器 |
327 | - int ret = avcodec_send_frame(codec_ctx_, pFrameOut); | |
328 | - av_frame_free(&pFrameOut); | |
181 | + int ret = avcodec_send_frame(codec_ctx_, frame); | |
329 | 182 | if (ret < 0) { |
330 | - LOG_ERROR("Error sending a frame to the encoder: {}", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
183 | + fprintf(stderr, "Error sending a frame to the encoder: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
331 | 184 | return false; |
332 | 185 | } |
333 | 186 | |
... | ... | @@ -338,36 +191,85 @@ bool FFRecoder::write_frame(AVFrame* frame) |
338 | 191 | if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) |
339 | 192 | return true; |
340 | 193 | else if (ret < 0) { |
341 | - LOG_ERROR("Error encoding a frame: {}", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
194 | + fprintf(stderr, "Error encoding a frame: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
342 | 195 | return false; |
343 | 196 | } |
344 | 197 | // 将pts缩放到输出流的time_base上 |
345 | 198 | av_packet_rescale_ts(&pkt, codec_ctx_->time_base, out_stream_->time_base); |
346 | 199 | pkt.stream_index = out_stream_->index; |
347 | - update_pts(&pkt); | |
348 | 200 | // 将数据写入到输出流 |
349 | 201 | ret = av_interleaved_write_frame(fmt_ctx_, &pkt); |
350 | - //ret = av_write_frame(fmt_ctx_, &pkt); | |
351 | 202 | av_packet_unref(&pkt); |
352 | 203 | if (ret < 0) { |
353 | - LOG_ERROR("Error while writing output packet: {}", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
204 | + fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
354 | 205 | return false; |
355 | 206 | } |
356 | - /* av_interleaved_write_frame(fmt_ctx_, nullptr); | |
357 | - avio_flush(fmt_ctx_->pb);*/ | |
358 | 207 | } |
359 | 208 | |
360 | 209 | return true; |
361 | 210 | } |
362 | 211 | |
363 | -bool FFRecoder::flush() | |
364 | -{ | |
365 | - return write_frame(nullptr); | |
212 | +static double a2d(AVRational a) { | |
213 | + return a.den / a.num; | |
214 | +} | |
215 | + | |
216 | +void FFRecoder::calc_pkt_ts(AVPacket* pkt, int frame_index) { | |
217 | + //Duration between 2 frames (us) | |
218 | + int64_t calc_duration=(double)AV_TIME_BASE/m_fps; | |
219 | + //Parameters | |
220 | + pkt->pts=(double)(frame_index*calc_duration)/(double)(av_q2d(codec_ctx_->time_base)*AV_TIME_BASE); | |
221 | + pkt->dts=pkt->pts; | |
222 | + pkt->duration=(double)calc_duration/(double)(av_q2d(codec_ctx_->time_base)*AV_TIME_BASE); | |
223 | +} | |
224 | + | |
225 | +bool FFRecoder::write_pkt(AVPacket* new_pkt) { | |
226 | + frame_nb++; | |
227 | + calc_pkt_ts(new_pkt, frame_nb); | |
228 | + new_pkt->pts = av_rescale_q_rnd(new_pkt->pts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
229 | + new_pkt->dts = av_rescale_q_rnd(new_pkt->dts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
230 | + new_pkt->duration = av_rescale_q(new_pkt->duration, codec_ctx_->time_base, out_stream_->time_base); | |
231 | + new_pkt->stream_index = out_stream_->index; | |
232 | + // 将数据写入到输出流 | |
233 | + int ret = av_interleaved_write_frame(fmt_ctx_, new_pkt); | |
234 | + | |
235 | + char errbuf[64]{ 0 }; | |
236 | + if (ret < 0) { | |
237 | + fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
238 | + return false; | |
239 | + } | |
240 | + | |
241 | + return true; | |
366 | 242 | } |
367 | 243 | |
368 | -bool FFRecoder::flush_pkt() | |
244 | +bool FFRecoder::write_pkt_data(const uint8_t* pkt_data, int pkt_size) { | |
245 | + AVPacket* new_pkt = av_packet_alloc(); | |
246 | + av_new_packet(new_pkt, pkt_size); | |
247 | + memcpy(new_pkt->data, pkt_data, pkt_size); | |
248 | + | |
249 | + frame_nb++; | |
250 | + calc_pkt_ts(new_pkt, frame_nb); | |
251 | + new_pkt->pts = av_rescale_q_rnd(new_pkt->pts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
252 | + new_pkt->dts = av_rescale_q_rnd(new_pkt->dts, codec_ctx_->time_base, out_stream_->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); | |
253 | + new_pkt->duration = av_rescale_q(new_pkt->duration, codec_ctx_->time_base, out_stream_->time_base); | |
254 | + new_pkt->stream_index = out_stream_->index; | |
255 | + // 将数据写入到输出流 | |
256 | + int ret = av_interleaved_write_frame(fmt_ctx_, new_pkt); | |
257 | + | |
258 | + av_packet_free(&new_pkt); | |
259 | + new_pkt = nullptr; | |
260 | + | |
261 | + char errbuf[64]{ 0 }; | |
262 | + if (ret < 0) { | |
263 | + fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
264 | + return false; | |
265 | + } | |
266 | + | |
267 | + return true; | |
268 | +} | |
269 | + | |
270 | +bool FFRecoder::flush() | |
369 | 271 | { |
370 | - return av_write_frame(fmt_ctx_, nullptr); | |
272 | + return write_frame(nullptr); | |
371 | 273 | } |
372 | 274 | |
373 | 275 | bool FFRecoder::bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p) |
... | ... | @@ -375,25 +277,30 @@ bool FFRecoder::bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_ |
375 | 277 | // 分配转换上下文 |
376 | 278 | thread_local std::tuple<int,int,int> params{ 0, 0, 0 }; |
377 | 279 | thread_local std::unique_ptr<SwsContext, decltype(&sws_freeContext)> sws_context{ nullptr, &sws_freeContext }; |
378 | - | |
379 | - std::tuple<int, int, int> new_params{ width_, height_, av_image_get_linesize(AV_PIX_FMT_YUV420P, width_, 0) }; | |
280 | + | |
281 | + std::tuple<int,int,int> new_params{ width_, height_, av_image_get_linesize(AV_PIX_FMT_YUV420P, width_, 0) }; | |
380 | 282 | if (!sws_context || params != new_params) |
381 | 283 | { |
382 | 284 | sws_context.reset(sws_getContext(width_, height_, AV_PIX_FMT_BGR24, width_, height_, |
383 | 285 | AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr)); |
384 | 286 | params = new_params; |
385 | 287 | } |
288 | + | |
386 | 289 | // 转换格式 |
387 | 290 | const int stride = std::get<2>(params);//Y平面一行的数据长度 |
388 | - //const int ret = sws_scale(sws_context.get(), | |
389 | - // std::array<const uint8_t* const>{ buf_bgr }.data(),/* bgr数据只有一个平面 */ | |
390 | - // std::array{ width_ * 3 }.data(),/* BGR所以图像宽度*3 */ | |
391 | - // 0, height_, | |
392 | - // std::array{ buf_420p, buf_420p + y_size_, buf_420p + y_size_ + uv_size_ }.data(),/* YUV三个平面的起始地址 */ | |
393 | - // std::array{ stride, stride / 2, stride / 2 }.data());/* YUV每个平面中一行的宽度 */ | |
394 | - const int rgba_linesize = width_ * 3; | |
395 | - int yuv_linesize[3] = { stride, stride / 2, stride / 2 }; | |
396 | - int ret = sws_scale(sws_context.get(), (const uint8_t* const*)buf_bgr, &rgba_linesize, 0, height_, (uint8_t* const*)buf_420p, yuv_linesize); | |
397 | - | |
398 | - return 0; | |
291 | + const int ret = sws_scale(sws_context.get(), | |
292 | + &buf_bgr,/* bgr数据只有一个平面 */ | |
293 | + std::array<int, 1> {width_ * 3}.data(),/* BGR所以图像宽度*3 */ | |
294 | + 0, height_, | |
295 | + std::array<uint8_t* const, 3>{ buf_420p, buf_420p + y_size_, buf_420p + y_size_ + uv_size_ }.data(),/* YUV三个平面的起始地址 */ | |
296 | + std::array<int, 3>{ stride, stride / 2, stride / 2 }.data() | |
297 | + );/* YUV每个平面中一行的宽度 */ | |
298 | + | |
299 | + return ret >= 0; | |
300 | +} | |
301 | + | |
302 | +bool FFRecoder::close() | |
303 | +{ | |
304 | + flush(); | |
305 | + uninit(); | |
399 | 306 | } |
400 | 307 | \ No newline at end of file | ... | ... |
src/decoder/dvpp/FFRecoder.h
1 | 1 | #pragma once |
2 | 2 | #include <memory> |
3 | 3 | |
4 | -#include "depend_headers.h" | |
4 | +class AVFrame; | |
5 | +class AVStream; | |
6 | +class AVCodecContext; | |
7 | +class AVFormatContext; | |
8 | +class AVPacket; | |
5 | 9 | |
6 | 10 | class FFRecoder |
7 | 11 | { |
8 | 12 | public: |
9 | 13 | FFRecoder(); |
10 | - virtual ~FFRecoder(); | |
14 | + ~FFRecoder(); | |
11 | 15 | |
12 | - bool init(int w, int h, AVRational time_base, AVCodecContext* avctx, const char* outfile_name); | |
16 | + bool init(int w, int h, int fps, int bit_rate, const char* outfile_name); | |
13 | 17 | void uninit(); |
14 | 18 | bool write_image(const uint8_t* bgr); |
15 | 19 | bool write_yuv(const uint8_t* yuv_data); |
16 | - bool write_frame(AVFrame* frame); | |
20 | + bool write_frame(const AVFrame* frame); | |
21 | + bool write_pkt(AVPacket* pkt); | |
22 | + bool write_pkt_data(const uint8_t* data, int size); | |
17 | 23 | bool flush(); |
18 | - | |
19 | - // AVPacket 方式 | |
20 | - bool init(AVStream* stream, AVCodecContext* avctx, const char* outfile_name); | |
21 | - bool write_pkt(AVPacket *pkt); | |
22 | - bool flush_pkt(); | |
23 | - void release(); | |
24 | + bool close(); | |
24 | 25 | |
25 | 26 | private: |
26 | 27 | bool bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p); |
27 | - void update_pts(AVPacket* pkt); | |
28 | + void calc_pkt_ts(AVPacket* pkt, int frame_index); | |
28 | 29 | |
29 | 30 | private: |
30 | 31 | int width_; |
... | ... | @@ -37,17 +38,7 @@ private: |
37 | 38 | AVStream* out_stream_; |
38 | 39 | AVFrame* yuv_frame_; |
39 | 40 | |
40 | - SwsContext * img_convert_ctx; | |
41 | - //AVFrame* pFrameOut; | |
42 | - uint8_t * out_buffer; | |
43 | - | |
44 | - bool bFirstFrame; | |
45 | - int64_t last_src_pts; | |
46 | - int64_t last_pts; | |
47 | - | |
48 | - int64_t first_pts; | |
49 | - int64_t first_dts; | |
41 | + int m_fps{1}; | |
50 | 42 | |
51 | - int64_t frame_index{0}; | |
52 | - AVStream* m_inStream; | |
43 | + int frame_nb{0}; | |
53 | 44 | }; |
54 | 45 | \ No newline at end of file | ... | ... |
src/decoder/dvpp/FFRecoder2.cpp deleted
1 | -// FFRecoder2.cpp | |
2 | -#include "FFRecoder2.h" | |
3 | -#include <tuple> | |
4 | -#include <array> | |
5 | -#include <vector> | |
6 | - | |
7 | -extern "C" { | |
8 | -#include <libavcodec/avcodec.h> | |
9 | -#include <libavformat/avformat.h> | |
10 | -#include <libavutil/opt.h> | |
11 | -#include <libavutil/timestamp.h> | |
12 | -#include <libavutil/imgutils.h> | |
13 | -#include <libswscale/swscale.h> | |
14 | -} | |
15 | - | |
16 | - | |
17 | -FFRecoder2::FFRecoder2() | |
18 | - :width_{}, | |
19 | - height_{}, | |
20 | - y_size_{}, | |
21 | - uv_size_{}, | |
22 | - pts_{}, | |
23 | - codec_ctx_{ nullptr }, | |
24 | - fmt_ctx_{ nullptr }, | |
25 | - out_stream_{ nullptr }, | |
26 | - yuv_frame_{ nullptr } | |
27 | -{ | |
28 | -} | |
29 | - | |
30 | -FFRecoder2::~FFRecoder2() | |
31 | -{ | |
32 | - uninit(); | |
33 | -} | |
34 | - | |
35 | - | |
36 | -bool FFRecoder2::init(int w, int h, int fps, int bit_rate, const char* outfile_name) | |
37 | -{ | |
38 | - uninit(); | |
39 | - | |
40 | - width_ = w; | |
41 | - height_ = h; | |
42 | - y_size_ = w * h; | |
43 | - uv_size_ = y_size_ / 4; | |
44 | - | |
45 | - // [1] 创建解码器 | |
46 | - const AVCodec* encoder = avcodec_find_encoder(AV_CODEC_ID_H264); | |
47 | - if (!encoder) { | |
48 | - fprintf(stderr, "Find encoder AV_CODEC_ID_H264 failed!\n"); | |
49 | - return false; | |
50 | - } | |
51 | - // 获取解码器上下文 | |
52 | - codec_ctx_ = avcodec_alloc_context3(encoder); | |
53 | - if (!codec_ctx_) { | |
54 | - fprintf(stderr, "Alloc context for encoder contx failed!\n"); | |
55 | - return false; | |
56 | - } | |
57 | - // 设置解码器上下文参数 | |
58 | - codec_ctx_->bit_rate = bit_rate; | |
59 | - codec_ctx_->width = width_; | |
60 | - codec_ctx_->height = height_; | |
61 | - codec_ctx_->time_base = AVRational{ 1, fps }; | |
62 | - codec_ctx_->gop_size = 50; | |
63 | - codec_ctx_->max_b_frames = 0; | |
64 | - codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P; | |
65 | - codec_ctx_->thread_count = 4; | |
66 | - codec_ctx_->qmin = 10; | |
67 | - codec_ctx_->qmax = 51; | |
68 | - codec_ctx_->qcompress = 0.6f; | |
69 | - codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
70 | - | |
71 | - //av_opt_set(codec_ctx_->priv_data, "preset", "ultrafast", 0); | |
72 | - av_opt_set(codec_ctx_->priv_data, "tune", "zerolatency", 0); | |
73 | - | |
74 | - // 打开解码器 | |
75 | - int ret = avcodec_open2(codec_ctx_, encoder, nullptr); | |
76 | - if (ret < 0) { | |
77 | - fprintf(stderr, "Open encoder failed!\n"); | |
78 | - return false; | |
79 | - } | |
80 | - | |
81 | - // [2] 创建输出上下文 | |
82 | - avformat_alloc_output_context2(&fmt_ctx_, nullptr, nullptr, outfile_name); | |
83 | - | |
84 | - // [3] 添加输出视频流 | |
85 | - out_stream_ = avformat_new_stream(fmt_ctx_, nullptr); | |
86 | - out_stream_->id = 0; | |
87 | - out_stream_->codecpar->codec_tag = 0; | |
88 | - avcodec_parameters_from_context(out_stream_->codecpar, codec_ctx_); | |
89 | - | |
90 | - av_dump_format(fmt_ctx_, out_stream_->id, outfile_name, 1); | |
91 | - | |
92 | - // 创建YUV格式帧 | |
93 | - yuv_frame_ = av_frame_alloc(); | |
94 | - yuv_frame_->format = AV_PIX_FMT_YUV420P; | |
95 | - yuv_frame_->width = width_; | |
96 | - yuv_frame_->height = height_; | |
97 | - // 为创建的YUV帧分配内存 | |
98 | - if (av_frame_get_buffer(yuv_frame_, 0) < 0) { | |
99 | - av_frame_free(&yuv_frame_); | |
100 | - yuv_frame_ = nullptr; | |
101 | - fprintf(stderr, "Frame get buffer failed!\n"); | |
102 | - return false; | |
103 | - } | |
104 | - | |
105 | - // [5] 打开输出视频文件并写入视频头信息 | |
106 | - if (avio_open(&fmt_ctx_->pb, outfile_name, AVIO_FLAG_WRITE) < 0) { | |
107 | - fprintf(stderr, "avio_open failed!\n"); | |
108 | - return false; | |
109 | - } | |
110 | - if (avformat_write_header(fmt_ctx_, nullptr) < 0) { | |
111 | - fprintf(stderr, "Write header failed!\n"); | |
112 | - return false; | |
113 | - } | |
114 | - | |
115 | - return true; | |
116 | -} | |
117 | - | |
118 | -void FFRecoder2::uninit() | |
119 | -{ | |
120 | - if (fmt_ctx_) { | |
121 | - av_write_trailer(fmt_ctx_); | |
122 | - avio_close(fmt_ctx_->pb); | |
123 | - avformat_free_context(fmt_ctx_); | |
124 | - fmt_ctx_ = nullptr; | |
125 | - } | |
126 | - | |
127 | - if (codec_ctx_) { | |
128 | - avcodec_close(codec_ctx_); | |
129 | - avcodec_free_context(&codec_ctx_); | |
130 | - codec_ctx_ = nullptr; | |
131 | - } | |
132 | - | |
133 | - if (yuv_frame_) { | |
134 | - av_frame_free(&yuv_frame_); | |
135 | - yuv_frame_ = nullptr; | |
136 | - } | |
137 | - | |
138 | - width_ = 0; | |
139 | - height_ = 0; | |
140 | - y_size_ = 0; | |
141 | - uv_size_ = 0; | |
142 | - pts_ = 0; | |
143 | -} | |
144 | - | |
145 | -bool FFRecoder2::write_image(const uint8_t* bgr) | |
146 | -{ | |
147 | - // 分配YUV格式数据的内存 | |
148 | - thread_local std::vector<uint8_t> yuv_data; | |
149 | - if (yuv_data.size() != y_size_ * 3 / 2) { | |
150 | - yuv_data.resize(y_size_ * 3 / 2); | |
151 | - } | |
152 | - // BGR格式转YUV格式 | |
153 | - bgr_to_yuv420p(bgr, yuv_data.data()); | |
154 | - | |
155 | - return write_yuv(yuv_data.data()); | |
156 | -} | |
157 | - | |
158 | -bool FFRecoder2::write_yuv(const uint8_t* yuv_data) | |
159 | -{ | |
160 | - //拷贝YUV数据到帧,由于帧数据存在内存对齐,故需逐行拷贝 | |
161 | - for (int i = 0; i < height_; i++) { | |
162 | - memcpy(yuv_frame_->data[0] + i * yuv_frame_->linesize[0], yuv_data + width_ * i, width_); | |
163 | - } | |
164 | - const int uv_stride = width_ / 2; | |
165 | - for (int i = 0; i < height_ / 2; i++) { | |
166 | - memcpy(yuv_frame_->data[1] + i * yuv_frame_->linesize[1], yuv_data + y_size_ + uv_stride * i, uv_stride); | |
167 | - memcpy(yuv_frame_->data[2] + i * yuv_frame_->linesize[2], yuv_data + y_size_ + uv_size_ + uv_stride * i, uv_stride); | |
168 | - } | |
169 | - | |
170 | - yuv_frame_->pts = pts_++; | |
171 | - | |
172 | - return write_frame(yuv_frame_); | |
173 | -} | |
174 | - | |
175 | -bool FFRecoder2::write_frame(const AVFrame* frame) | |
176 | -{ | |
177 | - char errbuf[64]{ 0 }; | |
178 | - // 将帧数据发送到编码器 | |
179 | - int ret = avcodec_send_frame(codec_ctx_, frame); | |
180 | - if (ret < 0) { | |
181 | - fprintf(stderr, "Error sending a frame to the encoder: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
182 | - return false; | |
183 | - } | |
184 | - | |
185 | - while (true) { | |
186 | - AVPacket pkt{ 0 }; | |
187 | - // 获取编码后的数据 | |
188 | - ret = avcodec_receive_packet(codec_ctx_, &pkt); | |
189 | - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) | |
190 | - return true; | |
191 | - else if (ret < 0) { | |
192 | - fprintf(stderr, "Error encoding a frame: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
193 | - return false; | |
194 | - } | |
195 | - // 将pts缩放到输出流的time_base上 | |
196 | - av_packet_rescale_ts(&pkt, codec_ctx_->time_base, out_stream_->time_base); | |
197 | - pkt.stream_index = out_stream_->index; | |
198 | - // 将数据写入到输出流 | |
199 | - ret = av_interleaved_write_frame(fmt_ctx_, &pkt); | |
200 | - av_packet_unref(&pkt); | |
201 | - if (ret < 0) { | |
202 | - fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
203 | - return false; | |
204 | - } | |
205 | - } | |
206 | - | |
207 | - return true; | |
208 | -} | |
209 | - | |
210 | -static double a2d(AVRational a) { | |
211 | - return a.den / a.num; | |
212 | -} | |
213 | - | |
214 | -bool FFRecoder2::write_pkt(AVPacket* pkt) { | |
215 | - frame_nb++; | |
216 | - pkt->duration = int(a2d(codec_ctx_->time_base)); | |
217 | - pkt->pts = frame_nb; | |
218 | - // 将pts缩放到输出流的time_base上 | |
219 | - av_packet_rescale_ts(pkt, codec_ctx_->time_base, out_stream_->time_base); | |
220 | - pkt->stream_index = out_stream_->index; | |
221 | - // 将数据写入到输出流 | |
222 | - int ret = av_interleaved_write_frame(fmt_ctx_, pkt); | |
223 | - | |
224 | - char errbuf[64]{ 0 }; | |
225 | - if (ret < 0) { | |
226 | - fprintf(stderr, "Error while writing output packet: %s\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); | |
227 | - return false; | |
228 | - } | |
229 | - | |
230 | - return true; | |
231 | -} | |
232 | - | |
233 | -bool FFRecoder2::flush() | |
234 | -{ | |
235 | - return write_frame(nullptr); | |
236 | -} | |
237 | - | |
238 | -bool FFRecoder2::bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p) | |
239 | -{ | |
240 | - // 分配转换上下文 | |
241 | - thread_local std::tuple<int,int,int> params{ 0, 0, 0 }; | |
242 | - thread_local std::unique_ptr<SwsContext, decltype(&sws_freeContext)> sws_context{ nullptr, &sws_freeContext }; | |
243 | - | |
244 | - std::tuple<int,int,int> new_params{ width_, height_, av_image_get_linesize(AV_PIX_FMT_YUV420P, width_, 0) }; | |
245 | - if (!sws_context || params != new_params) | |
246 | - { | |
247 | - sws_context.reset(sws_getContext(width_, height_, AV_PIX_FMT_BGR24, width_, height_, | |
248 | - AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr)); | |
249 | - params = new_params; | |
250 | - } | |
251 | - | |
252 | - // 转换格式 | |
253 | - const int stride = std::get<2>(params);//Y平面一行的数据长度 | |
254 | - const int ret = sws_scale(sws_context.get(), | |
255 | - &buf_bgr,/* bgr数据只有一个平面 */ | |
256 | - std::array<int, 1> {width_ * 3}.data(),/* BGR所以图像宽度*3 */ | |
257 | - 0, height_, | |
258 | - std::array<uint8_t* const, 3>{ buf_420p, buf_420p + y_size_, buf_420p + y_size_ + uv_size_ }.data(),/* YUV三个平面的起始地址 */ | |
259 | - std::array<int, 3>{ stride, stride / 2, stride / 2 }.data() | |
260 | - );/* YUV每个平面中一行的宽度 */ | |
261 | - | |
262 | - return ret >= 0; | |
263 | -} | |
264 | - | |
265 | -bool FFRecoder2::close() | |
266 | -{ | |
267 | - flush(); | |
268 | - uninit(); | |
269 | -} | |
270 | 0 | \ No newline at end of file |
src/decoder/dvpp/FFRecoder2.h deleted
1 | -#pragma once | |
2 | -#include <memory> | |
3 | - | |
4 | -class AVFrame; | |
5 | -class AVStream; | |
6 | -class AVCodecContext; | |
7 | -class AVFormatContext; | |
8 | -class AVPacket; | |
9 | - | |
10 | -class FFRecoder2 | |
11 | -{ | |
12 | -public: | |
13 | - FFRecoder2(); | |
14 | - ~FFRecoder2(); | |
15 | - | |
16 | - bool init(int w, int h, int fps, int bit_rate, const char* outfile_name); | |
17 | - void uninit(); | |
18 | - bool write_image(const uint8_t* bgr); | |
19 | - bool write_yuv(const uint8_t* yuv_data); | |
20 | - bool write_frame(const AVFrame* frame); | |
21 | - bool write_pkt(AVPacket* pkt); | |
22 | - bool flush(); | |
23 | - bool close(); | |
24 | - | |
25 | -private: | |
26 | - bool bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p); | |
27 | - | |
28 | -private: | |
29 | - int width_; | |
30 | - int height_; | |
31 | - int y_size_; | |
32 | - int uv_size_; | |
33 | - int pts_; | |
34 | - AVCodecContext* codec_ctx_; | |
35 | - AVFormatContext* fmt_ctx_; | |
36 | - AVStream* out_stream_; | |
37 | - AVFrame* yuv_frame_; | |
38 | - | |
39 | - int frame_nb{0}; | |
40 | -}; | |
41 | 0 | \ No newline at end of file |
src/decoder/dvpp/FFRecoderTaskManager.cpp
1 | 1 | #include "FFRecoderTaskManager.h" |
2 | 2 | #include <chrono> |
3 | 3 | |
4 | -struct RecodeThreadParam { | |
5 | - FFRecoderTaskManager* _this; | |
6 | - RecodeParam param; | |
7 | -}; | |
8 | - | |
9 | 4 | static long get_cur_time() { |
10 | 5 | |
11 | 6 | chrono::time_point<chrono::system_clock, chrono::milliseconds> tpMicro |
... | ... | @@ -69,68 +64,14 @@ bool FFRecoderTaskManager::init(int w, int h, int fps, int bit_rate) { |
69 | 64 | return true; |
70 | 65 | } |
71 | 66 | |
72 | -static AVPacket* packet_clone(AVPacket* pkt) { | |
73 | - AVPacket *new_pkt = av_packet_alloc(); | |
74 | - av_init_packet( new_pkt ); | |
75 | - av_new_packet(new_pkt, pkt->size); | |
76 | - memcpy(new_pkt->data, pkt->data, pkt->size); | |
77 | - new_pkt->size = pkt->size; | |
78 | - // new_pkt->pts = pkt->pts; | |
79 | - // new_pkt->dts = pkt->dts; | |
80 | - // new_pkt->stream_index = pkt->stream_index; | |
81 | - // new_pkt->duration = pkt->duration; | |
82 | - // new_pkt->pos = pkt->pos; | |
83 | - // new_pkt->flags = pkt->flags; | |
84 | - // av_copy_packet_side_data(new_pkt, pkt); | |
85 | - return new_pkt; | |
86 | -} | |
87 | - | |
88 | -static AVPacket* copy_packet(const AVPacket* src) | |
89 | -{ | |
90 | - AVPacket* dst = av_packet_alloc(); // 分配内存 | |
91 | - if (!dst) { | |
92 | - return NULL; | |
93 | - } | |
94 | - | |
95 | - // 复制所有字段 | |
96 | - av_packet_ref(dst, src); | |
97 | - | |
98 | - // 复制音视频数据 | |
99 | - dst->data = (uint8_t*)av_malloc(src->size); | |
100 | - memcpy(dst->data, src->data, src->size); | |
101 | - dst->size = src->size; | |
102 | - return dst; | |
103 | -} | |
104 | - | |
105 | 67 | void FFRecoderTaskManager::cache_pkt(AVPacket* pkt, long long frame_nb, string dec_name){ |
106 | 68 | if(m_bExit) { |
107 | 69 | // 任务退出了就不再缓存数据了 |
108 | 70 | return; |
109 | 71 | } |
110 | 72 | |
111 | - // 考虑到一个AVPacket中的数据并不很大,为减少与解码模块的耦合度,方便管理,这里做一个clone | |
112 | - // AVPacket *new_pkt = copy_packet(pkt); | |
113 | - | |
114 | - DataPacket* newDataPkt = new DataPacket(); | |
115 | - newDataPkt->pkt = pkt; | |
116 | - newDataPkt->frame_nb = frame_nb; | |
117 | - | |
118 | - if(is_key_frame(pkt)){ | |
119 | - // 越来越大的值 | |
120 | - newDataPkt->isKeyFrame = true; | |
121 | - LOG_INFO("[{}] - key frame_nb: {}", dec_name, frame_nb); | |
122 | - } else { | |
123 | - newDataPkt->isKeyFrame = false; | |
124 | - } | |
125 | - | |
126 | - AVPacket* npkt = newDataPkt->pkt; | |
127 | - if(npkt == nullptr) { | |
128 | - return ; | |
129 | - } else if (npkt->data == nullptr || npkt->size <= 0){ | |
130 | - return ; | |
131 | - } | |
132 | - | |
133 | 73 | std::lock_guard<std::mutex> l_info(m_pkt_list_short_mtx); |
74 | + DataPacket* newDataPkt = new DataPacket(pkt->data, pkt->size, frame_nb, is_key_frame(pkt)); | |
134 | 75 | m_pkt_list_short.push_back(newDataPkt); |
135 | 76 | } |
136 | 77 | |
... | ... | @@ -277,20 +218,11 @@ void FFRecoderTaskManager::recode_thread() { |
277 | 218 | break; |
278 | 219 | } |
279 | 220 | |
280 | - auto it = m_pkt_list.begin(); | |
281 | - while (it != it_data) { | |
282 | - DataPacket* dataPkt = m_pkt_list.front(); | |
283 | - delete dataPkt; | |
284 | - dataPkt = nullptr; | |
285 | - m_pkt_list.pop_front(); | |
286 | - it = m_pkt_list.begin(); | |
287 | - } | |
288 | - | |
289 | 221 | LOG_INFO("start frame_nb: {}", (*it_data)->frame_nb); |
290 | 222 | |
291 | 223 | string file_name = recoderinfo.recoderPath; |
292 | 224 | |
293 | - FFRecoder2 ffrecoder; | |
225 | + FFRecoder ffrecoder; | |
294 | 226 | bool bInit = ffrecoder.init(m_width, m_height, m_fps, m_bit_rate, file_name.c_str()); |
295 | 227 | if (!bInit) { |
296 | 228 | LOG_ERROR("ffrecoder init error : {} {} {}", recoderinfo.task_id, recoderinfo.object_id, recoderinfo.frame_nb); |
... | ... | @@ -308,16 +240,15 @@ void FFRecoderTaskManager::recode_thread() { |
308 | 240 | if(dataPkt->frame_nb > recoderinfo.frame_nb) { |
309 | 241 | break; |
310 | 242 | } |
311 | - AVPacket* pkt = dataPkt->pkt; | |
312 | - if(pkt == nullptr) { | |
313 | - LOG_ERROR("{} pkt is nullptr", recoderinfo.task_id); | |
314 | - continue; | |
315 | - } else if (pkt->data == nullptr || pkt->size <= 0){ | |
316 | - LOG_ERROR("{} pkt data is nullptr or size is {}", recoderinfo.task_id, pkt->size); | |
243 | + | |
244 | + if (dataPkt->pkt_data == nullptr || dataPkt->pkt_size <= 0){ | |
245 | + LOG_ERROR("{} pkt data is nullptr or size is {}", recoderinfo.task_id, dataPkt->pkt_size); | |
317 | 246 | continue; |
318 | 247 | } |
319 | 248 | |
320 | - ffrecoder.write_pkt(pkt); | |
249 | + // LOG_INFO("ref count: {}", av_buffer_get_ref_count(pkt->buf)); | |
250 | + | |
251 | + ffrecoder.write_pkt_data(dataPkt->pkt_data, dataPkt->pkt_size); | |
321 | 252 | count++; |
322 | 253 | end_frame_nb = (*it_save)->frame_nb; |
323 | 254 | } | ... | ... |
src/decoder/dvpp/FFRecoderTaskManager.h
1 | -#include "FFRecoder2.h" | |
1 | +#include "FFRecoder.h" | |
2 | 2 | |
3 | 3 | #include "../../ai_platform/common_header.h" |
4 | 4 | #include "depend_headers.h" |
... | ... | @@ -12,11 +12,6 @@ |
12 | 12 | |
13 | 13 | using namespace std; |
14 | 14 | |
15 | -struct RecodeParam { | |
16 | - AVRational time_base; | |
17 | - RecoderInfo recoderInfo; | |
18 | - AVCodecContext* avctx; | |
19 | -}; | |
20 | 15 | |
21 | 16 | typedef std::function<bool(const char *msg)> mq_callback_t; |
22 | 17 | |
... | ... | @@ -65,7 +60,7 @@ private: |
65 | 60 | |
66 | 61 | mq_callback_t mq_publish_func; |
67 | 62 | |
68 | - // FFRecoder2 | |
63 | + // FFRecoder | |
69 | 64 | int m_width; |
70 | 65 | int m_height; |
71 | 66 | int m_fps; | ... | ... |
src/decoder/dvpp/VpcUtils.cpp
... | ... | @@ -32,7 +32,6 @@ int VpcUtils::init(int devId){ |
32 | 32 | |
33 | 33 | m_devId = devId; |
34 | 34 | |
35 | - aclrtSetDevice(m_devId); | |
36 | 35 | aclrtCreateContext(&context_, m_devId); |
37 | 36 | |
38 | 37 | CHECK_AND_RETURN(aclrtSetCurrentContext(context_), "aclrtSetCurrentContext failed"); |
... | ... | @@ -54,7 +53,6 @@ int VpcUtils::init(int devId){ |
54 | 53 | |
55 | 54 | DvppDataMemory* VpcUtils::convert2bgr(acldvppPicDesc *inputDesc_, int out_width, int out_height, bool key_frame){ |
56 | 55 | |
57 | - aclrtSetDevice(m_devId); | |
58 | 56 | aclrtSetCurrentContext(context_); |
59 | 57 | |
60 | 58 | int out_buf_width = ALIGN_UP(out_width, 16) * 3; |
... | ... | @@ -107,7 +105,6 @@ DvppDataMemory* VpcUtils::convert2bgr(acldvppPicDesc *inputDesc_, int out_width, |
107 | 105 | |
108 | 106 | DvppDataMemory* VpcUtils::convert2bgr(DvppDataMemory* inMem){ |
109 | 107 | |
110 | - aclrtSetDevice(m_devId); | |
111 | 108 | aclrtSetCurrentContext(context_); |
112 | 109 | |
113 | 110 | int out_width = inMem->getWidth(); |
... | ... | @@ -174,7 +171,6 @@ DvppDataMemory* VpcUtils::convert2bgr(DvppDataMemory* inMem){ |
174 | 171 | |
175 | 172 | DvppDataMemory* VpcUtils::resize(acldvppPicDesc *inputDesc_, int out_width, int out_height){ |
176 | 173 | |
177 | - aclrtSetDevice(m_devId); | |
178 | 174 | aclrtSetCurrentContext(context_); |
179 | 175 | |
180 | 176 | int out_buf_width = ALIGN_UP(out_width, 16); | ... | ... |
src/decoder/dvpp/depend_headers.h
... | ... | @@ -27,9 +27,10 @@ extern "C" { |
27 | 27 | #include "libavutil/samplefmt.h" |
28 | 28 | #include "libavformat/avformat.h" |
29 | 29 | #include "libavcodec/avcodec.h" |
30 | - #include <libavutil/opt.h> | |
31 | - #include <libavutil/timestamp.h> | |
32 | - #include <libswscale/swscale.h> | |
30 | + #include "libavcodec/bsf.h" | |
31 | + #include "libavutil/opt.h" | |
32 | + #include "libavutil/timestamp.h" | |
33 | + #include "libswscale/swscale.h" | |
33 | 34 | } |
34 | 35 | |
35 | 36 | |
... | ... | @@ -40,16 +41,28 @@ extern "C" { |
40 | 41 | |
41 | 42 | |
42 | 43 | struct DataPacket { |
43 | - AVPacket* pkt {nullptr}; | |
44 | + uint8_t *pkt_data{nullptr}; | |
45 | + int pkt_size{0}; | |
44 | 46 | unsigned long long frame_nb{0}; |
45 | 47 | bool isKeyFrame{false}; |
46 | 48 | |
49 | + DataPacket(uint8_t *data, int size, unsigned long long frameNb, bool isKey) { | |
50 | + pkt_data = (uint8_t*) malloc(size); | |
51 | + memcpy(pkt_data, data, size); | |
52 | + pkt_size = size; | |
53 | + frame_nb = frameNb; | |
54 | + isKeyFrame = isKey; | |
55 | + } | |
56 | + | |
47 | 57 | ~DataPacket(){ |
48 | - if(pkt != nullptr) { | |
58 | + if(pkt_data != nullptr) { | |
49 | 59 | // LOG_INFO("free frame_nb:{}", frame_nb); |
50 | - av_packet_free(&pkt); | |
51 | - pkt = nullptr; | |
60 | + free(pkt_data); | |
61 | + pkt_data = nullptr; | |
52 | 62 | } |
63 | + pkt_size = 0; | |
64 | + frame_nb = 0; | |
65 | + isKeyFrame = false; | |
53 | 66 | } |
54 | 67 | }; |
55 | 68 | ... | ... |