aboutsummaryrefslogtreecommitdiffstats
path: root/fftools/ffmpeg_filter.c
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2023-04-18 15:24:46 +0200
committerAnton Khirnov <anton@khirnov.net>2023-04-24 16:56:06 +0200
commiteb9ce9de3ba4422d781c79fb53c9f86cfddcc58b (patch)
treeced4ed7a64864a5bc182788cf471d7d3368e47b5 /fftools/ffmpeg_filter.c
parent0add05bd3ad93f3672cdf1004f30e96d29a5c470 (diff)
downloadffmpeg-eb9ce9de3ba4422d781c79fb53c9f86cfddcc58b.tar.gz
fftools/ffmpeg: move filtering functions to ffmpeg_filter
Diffstat (limited to 'fftools/ffmpeg_filter.c')
-rw-r--r--fftools/ffmpeg_filter.c202
1 files changed, 202 insertions, 0 deletions
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 7b3d9a490f..c39cf43774 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -36,6 +36,7 @@
#include "libavutil/pixfmt.h"
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
+#include "libavutil/timestamp.h"
// FIXME: YUV420P etc. are actually supported with full color range,
// yet the latter information isn't available here.
@@ -1300,3 +1301,204 @@ int filtergraph_is_simple(FilterGraph *fg)
{
return !fg->graph_desc;
}
+
+int reap_filters(int flush)
+{
+ AVFrame *filtered_frame = NULL;
+
+ /* Reap all buffers present in the buffer sinks */
+ for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
+ AVFilterContext *filter;
+ int ret = 0;
+
+ if (!ost->filter || !ost->filter->graph->graph)
+ continue;
+ filter = ost->filter->filter;
+
+ filtered_frame = ost->filtered_frame;
+
+ while (1) {
+ ret = av_buffersink_get_frame_flags(filter, filtered_frame,
+ AV_BUFFERSINK_FLAG_NO_REQUEST);
+ if (ret < 0) {
+ if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret));
+ } else if (flush && ret == AVERROR_EOF) {
+ if (av_buffersink_get_type(filter) == AVMEDIA_TYPE_VIDEO)
+ enc_frame(ost, NULL);
+ }
+ break;
+ }
+ if (ost->finished) {
+ av_frame_unref(filtered_frame);
+ continue;
+ }
+
+ if (filtered_frame->pts != AV_NOPTS_VALUE) {
+ AVRational tb = av_buffersink_get_time_base(filter);
+ ost->filter->last_pts = av_rescale_q(filtered_frame->pts, tb,
+ AV_TIME_BASE_Q);
+ filtered_frame->time_base = tb;
+
+ if (debug_ts)
+ av_log(NULL, AV_LOG_INFO, "filter_raw -> pts:%s pts_time:%s time_base:%d/%d\n",
+ av_ts2str(filtered_frame->pts),
+ av_ts2timestr(filtered_frame->pts, &tb),
+ tb.num, tb.den);
+ }
+
+ enc_frame(ost, filtered_frame);
+ av_frame_unref(filtered_frame);
+ }
+ }
+
+ return 0;
+}
+
+int ifilter_send_eof(InputFilter *ifilter, int64_t pts)
+{
+ int ret;
+
+ ifilter->eof = 1;
+
+ if (ifilter->filter) {
+ ret = av_buffersrc_close(ifilter->filter, pts, AV_BUFFERSRC_FLAG_PUSH);
+ if (ret < 0)
+ return ret;
+ } else {
+ // the filtergraph was never configured
+ if (ifilter->format < 0) {
+ ret = ifilter_parameters_from_codecpar(ifilter, ifilter->ist->par);
+ if (ret < 0)
+ return ret;
+ }
+ if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ return 0;
+}
+
+int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int keep_reference)
+{
+ FilterGraph *fg = ifilter->graph;
+ AVFrameSideData *sd;
+ int need_reinit, ret;
+ int buffersrc_flags = AV_BUFFERSRC_FLAG_PUSH;
+
+ if (keep_reference)
+ buffersrc_flags |= AV_BUFFERSRC_FLAG_KEEP_REF;
+
+ /* determine if the parameters for this input changed */
+ need_reinit = ifilter->format != frame->format;
+
+ switch (ifilter->ist->par->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ need_reinit |= ifilter->sample_rate != frame->sample_rate ||
+ av_channel_layout_compare(&ifilter->ch_layout, &frame->ch_layout);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ need_reinit |= ifilter->width != frame->width ||
+ ifilter->height != frame->height;
+ break;
+ }
+
+ if (!ifilter->ist->reinit_filters && fg->graph)
+ need_reinit = 0;
+
+ if (!!ifilter->hw_frames_ctx != !!frame->hw_frames_ctx ||
+ (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data))
+ need_reinit = 1;
+
+ if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
+ if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9))
+ need_reinit = 1;
+ } else if (ifilter->displaymatrix)
+ need_reinit = 1;
+
+ if (need_reinit) {
+ ret = ifilter_parameters_from_frame(ifilter, frame);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* (re)init the graph if possible, otherwise buffer the frame and return */
+ if (need_reinit || !fg->graph) {
+ if (!ifilter_has_all_input_formats(fg)) {
+ AVFrame *tmp = av_frame_clone(frame);
+ if (!tmp)
+ return AVERROR(ENOMEM);
+
+ ret = av_fifo_write(ifilter->frame_queue, &tmp, 1);
+ if (ret < 0)
+ av_frame_free(&tmp);
+
+ return ret;
+ }
+
+ ret = reap_filters(1);
+ if (ret < 0 && ret != AVERROR_EOF) {
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ ret = configure_filtergraph(fg);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error reinitializing filters!\n");
+ return ret;
+ }
+ }
+
+ ret = av_buffersrc_add_frame_flags(ifilter->filter, frame, buffersrc_flags);
+ if (ret < 0) {
+ if (ret != AVERROR_EOF)
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+int fg_transcode_step(FilterGraph *graph, InputStream **best_ist)
+{
+ int i, ret;
+ int nb_requests, nb_requests_max = 0;
+ InputFilter *ifilter;
+ InputStream *ist;
+
+ *best_ist = NULL;
+ ret = avfilter_graph_request_oldest(graph->graph);
+ if (ret >= 0)
+ return reap_filters(0);
+
+ if (ret == AVERROR_EOF) {
+ ret = reap_filters(1);
+ for (i = 0; i < graph->nb_outputs; i++)
+ close_output_stream(graph->outputs[i]->ost);
+ return ret;
+ }
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+
+ for (i = 0; i < graph->nb_inputs; i++) {
+ ifilter = graph->inputs[i];
+ ist = ifilter->ist;
+ if (input_files[ist->file_index]->eagain ||
+ input_files[ist->file_index]->eof_reached)
+ continue;
+ nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter);
+ if (nb_requests > nb_requests_max) {
+ nb_requests_max = nb_requests;
+ *best_ist = ist;
+ }
+ }
+
+ if (!*best_ist)
+ for (i = 0; i < graph->nb_outputs; i++)
+ graph->outputs[i]->ost->unavailable = 1;
+
+ return 0;
+}