You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.4 KiB
104 lines
3.4 KiB
//
|
|
// Created by xu fulong on 2022/9/9.
|
|
//
|
|
|
|
#include "ff_http_pusher.h"
|
|
|
|
#define PUSH_TAG "HttpPusher"
|
|
|
|
int FFHttpPusher::open(const char *inputPath, const char *outputPath) {
|
|
int ret;
|
|
|
|
avformat_network_init();
|
|
ret = avformat_open_input(&inFormatCtx, inputPath, nullptr, nullptr);
|
|
if (ret < 0) {
|
|
LOGE(PUSH_TAG, "avformat_open_input err=%s", av_err2str(ret));
|
|
return ret;
|
|
}
|
|
avformat_find_stream_info(inFormatCtx, nullptr);
|
|
av_dump_format(inFormatCtx, 0, inputPath, 0);
|
|
ret = avformat_alloc_output_context2(&outFormatCtx, nullptr, "flv", outputPath);
|
|
if (ret < 0 || !outFormatCtx) {
|
|
LOGE(PUSH_TAG, "alloc format_context err=%s", av_err2str(ret));
|
|
return ret;
|
|
}
|
|
|
|
for (int i = 0; i < inFormatCtx->nb_streams; ++i) {
|
|
AVStream *in_stream = inFormatCtx->streams[i];
|
|
const auto *codec = in_stream->codec->codec;
|
|
AVStream *out_stream = avformat_new_stream(outFormatCtx, codec);
|
|
avcodec_parameters_from_context(out_stream->codecpar, in_stream->codec);
|
|
if (outFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) {
|
|
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
|
}
|
|
out_stream->codecpar->codec_tag = 0;
|
|
}
|
|
|
|
if (!(outFormatCtx->oformat->flags & AVFMT_NOFILE)) {
|
|
ret = avio_open2(&outFormatCtx->pb, outputPath, AVIO_FLAG_WRITE, nullptr, nullptr);
|
|
if (ret < 0) {
|
|
LOGE(PUSH_TAG, "avio open error=%s", av_err2str(ret));
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ret = avformat_write_header(outFormatCtx, nullptr);
|
|
if (ret < 0) {
|
|
LOGE(PUSH_TAG, "avformat_write_header err=%s", av_err2str(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void rescale(AVFormatContext *in_format_ctx, AVFormatContext *out_format_ctx, AVPacket *packet) {
|
|
AVStream *in_stream = in_format_ctx->streams[packet->stream_index];
|
|
AVStream *out_stream = out_format_ctx->streams[packet->stream_index];
|
|
|
|
packet->pts = av_rescale_q(packet->pts, in_stream->time_base, out_stream->time_base);
|
|
packet->dts = av_rescale_q(packet->dts, in_stream->time_base, out_stream->time_base);
|
|
packet->duration = av_rescale_q(packet->duration, in_stream->time_base, out_stream->time_base);
|
|
packet->pos = -1;
|
|
}
|
|
|
|
int FFHttpPusher::push() {
|
|
int ret;
|
|
int64_t startTime = av_gettime();
|
|
|
|
while (true) {
|
|
ret = av_read_frame(inFormatCtx, &packet);
|
|
if (ret < 0) {
|
|
LOGE(PUSH_TAG, "av_read_frame err=%s", av_err2str(ret));
|
|
break;
|
|
}
|
|
|
|
AVRational time_base = inFormatCtx->streams[packet.stream_index]->time_base;
|
|
int64_t pts_time = av_rescale_q(packet.pts, time_base, AV_TIME_BASE_Q);
|
|
int64_t cur_time = av_gettime() - startTime;
|
|
if (pts_time > cur_time) {
|
|
av_usleep((unsigned int)(pts_time - cur_time));
|
|
}
|
|
|
|
rescale(inFormatCtx, outFormatCtx, &packet);
|
|
|
|
ret = av_interleaved_write_frame(outFormatCtx, &packet);
|
|
if (ret < 0) {
|
|
LOGE(PUSH_TAG, "write frame err=%s", av_err2str(ret));
|
|
break;
|
|
}
|
|
|
|
av_packet_unref(&packet);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void FFHttpPusher::close() {
|
|
if (outFormatCtx) {
|
|
av_write_trailer(outFormatCtx);
|
|
avformat_close_input(&outFormatCtx);
|
|
outFormatCtx = nullptr;
|
|
}
|
|
if (inFormatCtx) {
|
|
avformat_close_input(&inFormatCtx);
|
|
inFormatCtx = nullptr;
|
|
}
|
|
} |