mirror of
https://github.com/nyanmisaka/ffmpeg-rockchip.git
synced 2025-10-07 17:51:52 +08:00
ffmpeg: add video heartbeat capability to fix_sub_duration
Splits the currently handled subtitle at random access point packets that can be configured to follow a specific output stream. Currently only subtitle streams which are directly mapped into the same output in which the heartbeat stream resides are affected. This way the subtitle - which is known to be shown at this time can be split and passed to muxer before its full duration is yet known. This is also a drawback, as this essentially outputs multiple subtitles from a single input subtitle that continues over multiple random access points. Thus this feature should not be utilized in cases where subtitle output latency does not matter. Co-authored-by: Andrzej Nadachowski <andrzej.nadachowski@24i.com> Co-authored-by: Bernard Boulay <bernard.boulay@24i.com> Signed-off-by: Jan Ekström <jan.ekstrom@24i.com>
This commit is contained in:
148
fftools/ffmpeg.c
148
fftools/ffmpeg.c
@@ -126,6 +126,7 @@ typedef struct BenchmarkTimeStamps {
|
||||
int64_t sys_usec;
|
||||
} BenchmarkTimeStamps;
|
||||
|
||||
static int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt);
|
||||
static BenchmarkTimeStamps get_benchmark_time_stamps(void);
|
||||
static int64_t getmaxrss(void);
|
||||
static int ifilter_has_all_input_formats(FilterGraph *fg);
|
||||
@@ -953,6 +954,13 @@ static int encode_frame(OutputFile *of, OutputStream *ost, AVFrame *frame)
|
||||
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, &enc->time_base));
|
||||
}
|
||||
|
||||
if ((ret = trigger_fix_sub_duration_heartbeat(ost, pkt)) < 0) {
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Subtitle heartbeat logic failed in %s! (%s)\n",
|
||||
__func__, av_err2str(ret));
|
||||
exit_program(1);
|
||||
}
|
||||
|
||||
ost->data_size_enc += pkt->size;
|
||||
|
||||
ost->packets_encoded++;
|
||||
@@ -1912,6 +1920,16 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
|
||||
|
||||
opkt->duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->mux_timebase);
|
||||
|
||||
{
|
||||
int ret = trigger_fix_sub_duration_heartbeat(ost, pkt);
|
||||
if (ret < 0) {
|
||||
av_log(NULL, AV_LOG_ERROR,
|
||||
"Subtitle heartbeat logic failed in %s! (%s)\n",
|
||||
__func__, av_err2str(ret));
|
||||
exit_program(1);
|
||||
}
|
||||
}
|
||||
|
||||
of_output_packet(of, opkt, ost, 0);
|
||||
|
||||
ost->streamcopy_started = 1;
|
||||
@@ -2355,6 +2373,136 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int copy_av_subtitle(AVSubtitle *dst, AVSubtitle *src)
|
||||
{
|
||||
int ret = AVERROR_BUG;
|
||||
AVSubtitle tmp = {
|
||||
.format = src->format,
|
||||
.start_display_time = src->start_display_time,
|
||||
.end_display_time = src->end_display_time,
|
||||
.num_rects = 0,
|
||||
.rects = NULL,
|
||||
.pts = src->pts
|
||||
};
|
||||
|
||||
if (!src->num_rects)
|
||||
goto success;
|
||||
|
||||
if (!(tmp.rects = av_calloc(src->num_rects, sizeof(*tmp.rects))))
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
for (int i = 0; i < src->num_rects; i++) {
|
||||
AVSubtitleRect *src_rect = src->rects[i];
|
||||
AVSubtitleRect *dst_rect;
|
||||
|
||||
if (!(dst_rect = tmp.rects[i] = av_mallocz(sizeof(*tmp.rects[0])))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
tmp.num_rects++;
|
||||
|
||||
dst_rect->type = src_rect->type;
|
||||
dst_rect->flags = src_rect->flags;
|
||||
|
||||
dst_rect->x = src_rect->x;
|
||||
dst_rect->y = src_rect->y;
|
||||
dst_rect->w = src_rect->w;
|
||||
dst_rect->h = src_rect->h;
|
||||
dst_rect->nb_colors = src_rect->nb_colors;
|
||||
|
||||
if (src_rect->text)
|
||||
if (!(dst_rect->text = av_strdup(src_rect->text))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (src_rect->ass)
|
||||
if (!(dst_rect->ass = av_strdup(src_rect->ass))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
// SUBTITLE_BITMAP images are special in the sense that they
|
||||
// are like PAL8 images. first pointer to data, second to
|
||||
// palette. This makes the size calculation match this.
|
||||
size_t buf_size = src_rect->type == SUBTITLE_BITMAP && j == 1 ?
|
||||
AVPALETTE_SIZE :
|
||||
src_rect->h * src_rect->linesize[j];
|
||||
|
||||
if (!src_rect->data[j])
|
||||
continue;
|
||||
|
||||
if (!(dst_rect->data[j] = av_memdup(src_rect->data[j], buf_size))) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
dst_rect->linesize[j] = src_rect->linesize[j];
|
||||
}
|
||||
}
|
||||
|
||||
success:
|
||||
*dst = tmp;
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
avsubtitle_free(&tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fix_sub_duration_heartbeat(InputStream *ist, int64_t signal_pts)
|
||||
{
|
||||
int ret = AVERROR_BUG;
|
||||
int got_output = 1;
|
||||
AVSubtitle *prev_subtitle = &ist->prev_sub.subtitle;
|
||||
AVSubtitle subtitle;
|
||||
|
||||
if (!ist->fix_sub_duration || !prev_subtitle->num_rects ||
|
||||
signal_pts <= prev_subtitle->pts)
|
||||
return 0;
|
||||
|
||||
if ((ret = copy_av_subtitle(&subtitle, prev_subtitle)) < 0)
|
||||
return ret;
|
||||
|
||||
subtitle.pts = signal_pts;
|
||||
|
||||
return process_subtitle(ist, &subtitle, &got_output);
|
||||
}
|
||||
|
||||
static int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt)
|
||||
{
|
||||
OutputFile *of = output_files[ost->file_index];
|
||||
int64_t signal_pts = av_rescale_q(pkt->pts, ost->mux_timebase,
|
||||
AV_TIME_BASE_Q);
|
||||
|
||||
if (!ost->fix_sub_duration_heartbeat || !(pkt->flags & AV_PKT_FLAG_KEY))
|
||||
// we are only interested in heartbeats on streams configured, and
|
||||
// only on random access points.
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < of->nb_streams; i++) {
|
||||
OutputStream *iter_ost = of->streams[i];
|
||||
InputStream *ist = iter_ost->ist;
|
||||
int ret = AVERROR_BUG;
|
||||
|
||||
if (iter_ost == ost || !ist || !ist->decoding_needed ||
|
||||
ist->dec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE)
|
||||
// We wish to skip the stream that causes the heartbeat,
|
||||
// output streams without an input stream, streams not decoded
|
||||
// (as fix_sub_duration is only done for decoded subtitles) as
|
||||
// well as non-subtitle streams.
|
||||
continue;
|
||||
|
||||
if ((ret = fix_sub_duration_heartbeat(ist, signal_pts)) < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output,
|
||||
int *decode_failed)
|
||||
{
|
||||
|
Reference in New Issue
Block a user