uvgrtp-base/benchmarks/ffmpeg/latency_ffmpeg.cc

221 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <stdbool.h>
}
#include <chrono>
#include <thread>
extern void *get_mem(int argc, char **argv, size_t& len);
#define WIDTH 3840
#define HEIGHT 2160
#define FPS 120
#define SLEEP 8
#define CNT_VAL 1
std::chrono::high_resolution_clock::time_point latency_start, latency_end;
void receiver()
{
AVFormatContext* format_ctx = avformat_alloc_context();
AVCodecContext* codec_ctx = NULL;
int video_stream_index;
AVDictionary *d = NULL;
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0);
char buf[256];
/* input buffer size */
snprintf(buf, sizeof(buf), "%d", 40 * 1024 * 1024);
av_dict_set(&d, "buffer_size", buf, 32);
/* avioflags flags (input/output)
*
* Possible values:
* direct
* Reduce buffering. */
snprintf(buf, sizeof(buf), "direct");
av_dict_set(&d, "avioflags", buf, 32);
/* Reduce the latency introduced by buffering during initial input streams analysis. */
av_dict_set(&d, "nobuffer", NULL, 32);
/* Set probing size in bytes, i.e. the size of the data to analyze to get stream information.
*
* A higher value will enable detecting more information in case it is dispersed into the stream,
* but will increase latency. Must be an integer not lesser than 32. It is 5000000 by default. */
snprintf(buf, sizeof(buf), "%d", 256);
av_dict_set(&d, "probesize", buf, 32);
/* Set number of frames used to probe fps. */
snprintf(buf, sizeof(buf), "%d", 2);
av_dict_set(&d, "fpsprobesize", buf, 32);
if (avformat_open_input(&format_ctx, "../../examples/full/sdp/hevc.sdp", NULL, &d) != 0) {
return;
}
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
return;
}
//search video stream
for (size_t i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
}
size_t cnt = 0;
size_t size = 0;
AVPacket packet;
av_init_packet(&packet);
//start reading packets from stream and write them to file
av_read_play(format_ctx); //play RTSP
while (av_read_frame(format_ctx, &packet) >= 0) {
if (++cnt == CNT_VAL) {
latency_end = std::chrono::high_resolution_clock::now();
uint64_t diff = std::chrono::duration_cast<std::chrono::microseconds>(latency_end - latency_start).count();
fprintf(stdout, "%u + ", diff);
exit(EXIT_SUCCESS);
}
}
}
int main() {
avcodec_register_all();
av_register_all();
avformat_network_init();
enum AVCodecID codec_id = AV_CODEC_ID_H265;
AVCodec *codec;
AVCodecContext *c = NULL;
int i, ret, x, y, got_output;
AVFrame *frame;
AVPacket pkt;
auto recv = new std::thread(receiver);
codec = avcodec_find_encoder(codec_id);
c = avcodec_alloc_context3(codec);
c->width = HEIGHT;
c->height = WIDTH;
c->time_base.num = 1;
c->time_base.den = FPS;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->flags = AV_CODEC_FLAG_GLOBAL_HEADER;
avcodec_open2(c, codec, NULL);
frame = av_frame_alloc();
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
c->pix_fmt, 32);
AVFormatContext* avfctx;
AVOutputFormat* fmt = av_guess_format("rtp", NULL, NULL);
/* ret = avformat_alloc_output_context2(&avfctx, fmt, fmt->name, "rtp://10.21.25.2:8888"); */
ret = avformat_alloc_output_context2(&avfctx, fmt, fmt->name, "rtp://127.0.0.1:8888");
avio_open(&avfctx->pb, avfctx->filename, AVIO_FLAG_WRITE);
struct AVStream* stream = avformat_new_stream(avfctx, codec);
stream->codecpar->width = WIDTH;
stream->codecpar->height = HEIGHT;
stream->codecpar->codec_id = AV_CODEC_ID_HEVC;
stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
stream->time_base.num = 1;
stream->time_base.den = FPS;
char buf[256];
AVDictionary *d = NULL;
snprintf(buf, sizeof(buf), "%d", 40 * 1024 * 1024);
av_dict_set(&d, "buffer_size", buf, 32);
/* Flush the underlying I/O stream after each packet.
*
* Default is -1 (auto), which means that the underlying protocol will decide,
* 1 enables it, and has the effect of reducing the latency,
* 0 disables it and may increase IO throughput in some cases. */
snprintf(buf, sizeof(buf), "%d", 1);
av_dict_set(&d, "flush_packets", NULL, 32);
/* Set maximum buffering duration for interleaving. The duration is expressed in microseconds,
* and defaults to 10000000 (10 seconds).
*
* To ensure all the streams are interleaved correctly, libavformat will wait until it has
* at least one packet for each stream before actually writing any packets to the output file.
* When some streams are "sparse" (i.e. there are large gaps between successive packets),
* this can result in excessive buffering.
*
* This field specifies the maximum difference between the timestamps of the first and
* the last packet in the muxing queue, above which libavformat will output a packet regardless of
* whether it has queued a packet for all the streams.
*
* If set to 0, libavformat will continue buffering packets until it has a packet for each stream,
* regardless of the maximum timestamp difference between the buffered packets. */
snprintf(buf, sizeof(buf), "%d", 1000);
av_dict_set(&d, "max_interleave_delta", buf, 32);
/* avioflags flags (input/output)
*
* Possible values:
* direct
* Reduce buffering. */
snprintf(buf, sizeof(buf), "direct");
av_dict_set(&d, "avioflags", buf, 32);
(void)avformat_write_header(avfctx, &d);
size_t len = 0;
void *mem = get_mem(NULL, NULL, len);
uint64_t chunk_size = 0, diff = 0, counter = 0;
std::chrono::high_resolution_clock::time_point start, fpt_start, fpt_end, end;
start = std::chrono::high_resolution_clock::now();
for (size_t rounds = 0; rounds < 1; ++rounds) {
for (size_t i = 0; i < len; ) {
memcpy(&chunk_size, (uint8_t *)mem + i, sizeof(uint64_t));
i += sizeof(uint64_t);
if (++counter == CNT_VAL) {
latency_start = std::chrono::high_resolution_clock::now();
}
av_init_packet(&pkt);
pkt.data = (uint8_t *)mem + i;
pkt.size = chunk_size;
av_write_frame(avfctx, &pkt);
i += chunk_size;
}
}
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100000));
}
}