Feature: replace ffmpeg_pusher.cpp with ff_http_pusher.cpp

pull/221/head
xufuji456 2 years ago
parent 6ebced2d49
commit 5ea59231e7
  1. 3
      app/src/main/cpp/CMakeLists.txt
  2. 104
      app/src/main/cpp/ff_http_pusher.cpp
  3. 39
      app/src/main/cpp/ff_http_pusher.h
  4. 6
      app/src/main/cpp/ffmpeg_jni_define.h
  5. 148
      app/src/main/cpp/ffmpeg_pusher.cpp
  6. 25
      app/src/main/cpp/ffmpeg_pusher_jni.cpp

@ -26,7 +26,6 @@ add_library( # Sets the name of the library.
ffmpeg/ffprobe.c
ffmpeg/ffmpeg_hw.c
video_player.cpp
ffmpeg_pusher.cpp
video_filter.c
ffprobe_cmd.cpp
video_cutting.cpp
@ -46,6 +45,8 @@ add_library( # Sets the name of the library.
common_media_jni.cpp
ff_audio_player.cpp
audio_player_jni.cpp
ff_http_pusher.cpp
ffmpeg_pusher_jni.cpp
)
add_library( ffmpeg

@ -0,0 +1,104 @@
//
// 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;
}
}

@ -0,0 +1,39 @@
//
// Created by xu fulong on 2022/9/9.
//
#ifndef FF_HTTP_PUSHER_H
#define FF_HTTP_PUSHER_H
#include "ffmpeg_jni_define.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/time.h"
#ifdef __cplusplus
}
#endif
class FFHttpPusher {
private:
AVFormatContext *inFormatCtx;
AVFormatContext *outFormatCtx;
AVPacket packet;
int video_index = -1;
int audio_index = -1;
public:
int open(const char *inputPath, const char *outputPath);
int push();
void close();
};
#endif //FF_HTTP_PUSHER_H

@ -35,8 +35,12 @@ extern "C" { \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
#define PUSHER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
extern "C" { \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_FFmpegPusher_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__)\
(JNIEnv *env, jobject thiz, ##__VA_ARGS__);\
} \
JNIEXPORT RETURN_TYPE JNICALL Java_com_frank_ffmpeg_FFmpegPusher_ ## FUNC_NAME \
(JNIEnv *env, jobject thiz, ##__VA_ARGS__) \
#define RETRIEVER_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
extern "C" { \

@ -1,148 +0,0 @@
//
// Created by frank on 2018/2/2.
//
#include <jni.h>
#include <string>
#include "ffmpeg_jni_define.h"
#define TAG "FFmpegPusher"
#ifdef __cplusplus
extern "C" {
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/time.h>
PUSHER_FUNC(jint, pushStream, jstring filePath, jstring liveUrl) {
int ret;
AVPacket packet;
int64_t start_time;
int video_index = -1;
int frame_index = 0;
const char *file_path;
const char *live_url;
AVFormatContext *in_format = nullptr;
AVFormatContext *out_format = nullptr;
file_path = env->GetStringUTFChars(filePath, nullptr);
live_url = env->GetStringUTFChars(liveUrl, nullptr);
avformat_network_init();
if ((ret = avformat_open_input(&in_format, file_path, nullptr, nullptr)) < 0) {
LOGE(TAG, "could not open input file...");
goto end;
}
if ((ret = avformat_find_stream_info(in_format, nullptr)) < 0) {
LOGE(TAG, "could not find stream info...");
goto end;
}
for (int i = 0; i < in_format->nb_streams; i++) {
if (in_format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_index = i;
break;
}
}
av_dump_format(in_format, 0, file_path, 0);
avformat_alloc_output_context2(&out_format, nullptr, "flv", live_url);
if (!out_format) {
LOGE(TAG, "could not alloc output context...");
ret = AVERROR_UNKNOWN;
goto end;
}
//Create output stream according to input stream
for (int i = 0; i < in_format->nb_streams; i++) {
AVStream *in_stream = in_format->streams[i];
AVStream *out_stream = avformat_new_stream(out_format, in_stream->codec->codec);
if (!out_stream) {
LOGE(TAG, "could not alloc output stream...");
ret = AVERROR_UNKNOWN;
goto end;
}
//Copy context
ret = avcodec_parameters_from_context(out_stream->codecpar, in_stream->codec);
if (ret < 0) {
LOGE(TAG, "could not copy context...");
goto end;
}
out_stream->codecpar->codec_tag = 0;
if (out_format->oformat->flags & AVFMT_GLOBALHEADER) {
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
if (!(out_format->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&out_format->pb, live_url, AVIO_FLAG_WRITE);
if (ret < 0) {
LOGE(TAG, "could not open output url '%s'", live_url);
goto end;
}
}
//Write header
ret = avformat_write_header(out_format, nullptr);
if (ret < 0) {
LOGE(TAG, "could not write header...");
goto end;
}
start_time = av_gettime();
while (true) {
AVStream *in_stream, *out_stream;
ret = av_read_frame(in_format, &packet);
if (ret < 0) {
break;
}
if (packet.stream_index == video_index) {
AVRational time_base = in_format->streams[video_index]->time_base;
AVRational time_base_q = {1, AV_TIME_BASE};
int64_t pts_time = av_rescale_q(packet.dts, time_base, time_base_q);
int64_t now_time = av_gettime() - start_time;
//sleep to keep waiting
if (pts_time > now_time) {
av_usleep((unsigned int) (pts_time - now_time));
}
}
in_stream = in_format->streams[packet.stream_index];
out_stream = out_format->streams[packet.stream_index];
//calculate: pts dts duration
packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base,
(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base,
(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
packet.duration = av_rescale_q(packet.duration, in_stream->time_base,
out_stream->time_base);
packet.pos = -1;
if (packet.stream_index == video_index) {
frame_index++;
LOGI(TAG, "write frame = %d", frame_index);
}
//Write a frame
ret = av_interleaved_write_frame(out_format, &packet);
if (ret < 0) {
LOGE(TAG, "could not write frame...");
break;
}
av_packet_unref(&packet);
}
//Write tail
av_write_trailer(out_format);
end:
if (out_format && !(out_format->flags & AVFMT_NOFILE)) {
avio_close(out_format->pb);
}
avformat_free_context(out_format);
avformat_close_input(&in_format);
env->ReleaseStringUTFChars(filePath, file_path);
env->ReleaseStringUTFChars(liveUrl, live_url);
return (ret < 0 && ret != AVERROR_EOF) ? -1 : 0;
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,25 @@
//
// Created by xu fulong on 2022/9/9.
//
#include <jni.h>
#include "ff_http_pusher.h"
PUSHER_FUNC(int, pushStream, jstring inputPath, jstring outputPath) {
int ret;
const char *input_path = env->GetStringUTFChars(inputPath, JNI_FALSE);
const char *output_path = env->GetStringUTFChars(outputPath, JNI_FALSE);
auto *httpPusher = new FFHttpPusher();
ret = httpPusher->open(input_path, output_path);
if (ret < 0) {
LOGE("HttpPusher", "open error=%d", ret);
return ret;
}
ret = httpPusher->push();
httpPusher->close();
env->ReleaseStringUTFChars(inputPath, input_path);
env->ReleaseStringUTFChars(outputPath, output_path);
return ret;
}
Loading…
Cancel
Save