mirror of https://github.com/FFmpeg/FFmpeg.git
Compare commits
24 Commits
d31983dc8e
...
746650dfe5
| Author | SHA1 | Date |
|---|---|---|
|
|
746650dfe5 | |
|
|
a979c9b935 | |
|
|
5ff8395e78 | |
|
|
433d18a1d9 | |
|
|
dec3cc0138 | |
|
|
e7cf188bb6 | |
|
|
9dcd25b7cd | |
|
|
cce85642c9 | |
|
|
c751ad2c36 | |
|
|
99ec0752d7 | |
|
|
ba0dc3d49e | |
|
|
7b18beb477 | |
|
|
7ac1b410e1 | |
|
|
6879c8ee5d | |
|
|
0242cb36a5 | |
|
|
00c23bafb0 | |
|
|
82c495fd15 | |
|
|
0f105b96a3 | |
|
|
909af3a571 | |
|
|
d8ffec5bf9 | |
|
|
d03483bd26 | |
|
|
afd927e0ca | |
|
|
0d11c5c2f9 | |
|
|
3d12d5682b |
|
|
@ -9,6 +9,7 @@ version <next>:
|
|||
- MPEG-H 3D Audio decoding via mpeghdec
|
||||
- D3D12 H.264 encoder
|
||||
- drawvg filter via libcairo
|
||||
- ffmpeg CLI tiled HEIF support
|
||||
|
||||
|
||||
version 8.0:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@ The last version increases of all libraries were on 2025-03-28
|
|||
|
||||
API changes, most recent first:
|
||||
|
||||
2025-10-30 - xxxxxxxxxx - lavc 62.17.100 - packet.h
|
||||
Add av_packet_side_data_from_frame() and av_packet_side_data_to_frame().
|
||||
|
||||
2025-10-xx - xxxxxxxxxx - lavu 60.16.100 - pixfmt.h
|
||||
Add AVCOL_TRC_EXT_BASE and AVCOL_TRC_L_LOG.
|
||||
Add AVCOL_TRC_EXT_BASE, AVCOL_TRC_V_LOG,
|
||||
AVCOL_PRI_EXT_BASE and AVCOL_PRI_V_GAMUT.
|
||||
|
||||
2025-10-xx - xxxxxxxxxx - lavu 60.15.100 - pixfmt.h
|
||||
Add AV_PIX_FMT_GRAY10MSB, AV_PIX_FMT_GRAY12MSB,
|
||||
|
|
|
|||
|
|
@ -13056,7 +13056,9 @@ Draw vector graphics on top of video frames, by executing a script written in
|
|||
a custom language called VGS (@emph{Vector Graphics Script}).
|
||||
|
||||
The documentation for the language can be found in
|
||||
@ref{,,drawvg - Language Reference,drawvg-reference}.
|
||||
@ref{,,drawvg - Language Reference,drawvg-reference}. A version of this reference
|
||||
with rendered examples can be found at the
|
||||
@uref{https://ayosec.github.io/ffmpeg-drawvg/playground/docs/langref.html, author's site}.
|
||||
|
||||
Graphics are rendered using the @uref{https://cairographics.org/,cario 2D
|
||||
graphics library}.
|
||||
|
|
|
|||
|
|
@ -1350,6 +1350,77 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
|
|||
return ret;
|
||||
}
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx)
|
||||
{
|
||||
int start_stream_group = 0, nb_stream_groups;
|
||||
int nb_matched = 0;
|
||||
|
||||
if (ss->idx >= 0)
|
||||
return 0;
|
||||
|
||||
switch (ss->stream_list) {
|
||||
case STREAM_LIST_STREAM_ID:
|
||||
case STREAM_LIST_ALL:
|
||||
case STREAM_LIST_PROGRAM:
|
||||
return 0;
|
||||
case STREAM_LIST_GROUP_ID:
|
||||
// <n-th> stream with given ID makes no sense and should be impossible to request
|
||||
av_assert0(ss->idx < 0);
|
||||
// return early if we know for sure the stream does not match
|
||||
if (stg->id != ss->list_id)
|
||||
return 0;
|
||||
start_stream_group = stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
case STREAM_LIST_GROUP_IDX:
|
||||
start_stream_group = ss->list_id >= 0 ? 0 : stg->index;
|
||||
nb_stream_groups = stg->index + 1;
|
||||
break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
for (int i = start_stream_group; i < nb_stream_groups; i++) {
|
||||
const AVStreamGroup *candidate = s->stream_groups[i];
|
||||
|
||||
if (ss->meta_key) {
|
||||
const AVDictionaryEntry *tag = av_dict_get(candidate->metadata,
|
||||
ss->meta_key, NULL, 0);
|
||||
|
||||
if (!tag)
|
||||
continue;
|
||||
if (ss->meta_val && strcmp(tag->value, ss->meta_val))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ss->usable_only) {
|
||||
switch (candidate->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
|
||||
const AVStreamGroupTileGrid *tg = candidate->params.tile_grid;
|
||||
if (!tg->coded_width || !tg->coded_height || !tg->nb_tiles ||
|
||||
!tg->width || !tg->height || !tg->nb_tiles)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ss->disposition &&
|
||||
(candidate->disposition & ss->disposition) != ss->disposition)
|
||||
continue;
|
||||
|
||||
if (stg == candidate)
|
||||
return ss->list_id < 0 || ss->list_id == nb_matched;
|
||||
|
||||
nb_matched++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id,
|
||||
AVFormatContext *s, AVStream *st, const AVCodec *codec,
|
||||
AVDictionary **dst, AVDictionary **opts_used)
|
||||
|
|
|
|||
|
|
@ -158,6 +158,10 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
|
|||
const AVFormatContext *s, const AVStream *st,
|
||||
void *logctx);
|
||||
|
||||
unsigned stream_group_specifier_match(const StreamSpecifier *ss,
|
||||
const AVFormatContext *s, const AVStreamGroup *stg,
|
||||
void *logctx);
|
||||
|
||||
void stream_specifier_uninit(StreamSpecifier *ss);
|
||||
|
||||
typedef struct SpecifierOpt {
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ static void frame_data_free(void *opaque, uint8_t *data)
|
|||
{
|
||||
FrameData *fd = (FrameData *)data;
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
avcodec_parameters_free(&fd->par_enc);
|
||||
|
||||
av_free(data);
|
||||
|
|
@ -429,6 +430,8 @@ static int frame_data_ensure(AVBufferRef **dst, int writable)
|
|||
|
||||
memcpy(fd, fd_src, sizeof(*fd));
|
||||
fd->par_enc = NULL;
|
||||
fd->side_data = NULL;
|
||||
fd->nb_side_data = 0;
|
||||
|
||||
if (fd_src->par_enc) {
|
||||
int ret = 0;
|
||||
|
|
@ -444,6 +447,16 @@ static int frame_data_ensure(AVBufferRef **dst, int writable)
|
|||
}
|
||||
}
|
||||
|
||||
if (fd_src->nb_side_data) {
|
||||
int ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
fd_src->side_data, fd_src->nb_side_data, 0);
|
||||
if (ret < 0) {
|
||||
av_buffer_unref(dst);
|
||||
av_buffer_unref(&src);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
av_buffer_unref(&src);
|
||||
} else {
|
||||
fd->dec.frame_num = UINT64_MAX;
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ typedef struct StreamMap {
|
|||
int disabled; /* 1 is this mapping is disabled by a negative map */
|
||||
int file_index;
|
||||
int stream_index;
|
||||
int group_index;
|
||||
char *linklabel; /* name of an output link, for mapping lavfi outputs */
|
||||
|
||||
ViewSpecifier vs;
|
||||
|
|
@ -299,6 +300,8 @@ enum OFilterFlags {
|
|||
// produce 24-bit audio
|
||||
OFILTER_FLAG_AUDIO_24BIT = (1 << 1),
|
||||
OFILTER_FLAG_AUTOSCALE = (1 << 2),
|
||||
OFILTER_FLAG_AUTOROTATE = (1 << 3),
|
||||
OFILTER_FLAG_CROP = (1 << 4),
|
||||
};
|
||||
|
||||
typedef struct OutputFilterOptions {
|
||||
|
|
@ -332,6 +335,11 @@ typedef struct OutputFilterOptions {
|
|||
enum AVColorRange color_range;
|
||||
enum AVAlphaMode alpha_mode;
|
||||
|
||||
unsigned crop_top;
|
||||
unsigned crop_bottom;
|
||||
unsigned crop_left;
|
||||
unsigned crop_right;
|
||||
|
||||
enum VideoSyncMethod vsync_method;
|
||||
AVRational frame_rate;
|
||||
AVRational max_frame_rate;
|
||||
|
|
@ -347,6 +355,9 @@ typedef struct OutputFilterOptions {
|
|||
const enum AVColorRange *color_ranges;
|
||||
const enum AVAlphaMode *alpha_modes;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
|
||||
// for simple filtergraphs only, view specifier passed
|
||||
// along to the decoder
|
||||
const ViewSpecifier *vs;
|
||||
|
|
@ -402,6 +413,11 @@ typedef struct FilterGraph {
|
|||
OutputFilter **outputs;
|
||||
int nb_outputs;
|
||||
|
||||
// true when the filtergraph is created internally for
|
||||
// purposes like stream group merging. Meant to be freed
|
||||
// if unbound.
|
||||
int is_internal;
|
||||
|
||||
const char *graph_desc;
|
||||
struct AVBPrint graph_print_buf;
|
||||
} FilterGraph;
|
||||
|
|
@ -491,6 +507,18 @@ typedef struct InputStream {
|
|||
int nb_filters;
|
||||
} InputStream;
|
||||
|
||||
typedef struct InputStreamGroup {
|
||||
const AVClass *class;
|
||||
|
||||
/* parent source */
|
||||
struct InputFile *file;
|
||||
|
||||
int index;
|
||||
|
||||
FilterGraph *fg;
|
||||
AVStreamGroup *stg;
|
||||
} InputStreamGroup;
|
||||
|
||||
typedef struct InputFile {
|
||||
const AVClass *class;
|
||||
|
||||
|
|
@ -512,6 +540,10 @@ typedef struct InputFile {
|
|||
* if new streams appear dynamically during demuxing */
|
||||
InputStream **streams;
|
||||
int nb_streams;
|
||||
|
||||
/* stream groups that ffmpeg is aware of; */
|
||||
InputStreamGroup **stream_groups;
|
||||
int nb_stream_groups;
|
||||
} InputFile;
|
||||
|
||||
enum forced_keyframes_const {
|
||||
|
|
@ -698,6 +730,9 @@ typedef struct FrameData {
|
|||
int64_t wallclock[LATENCY_PROBE_NB];
|
||||
|
||||
AVCodecParameters *par_enc;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
} FrameData;
|
||||
|
||||
extern InputFile **input_files;
|
||||
|
|
@ -802,7 +837,8 @@ int ofilter_bind_enc(OutputFilter *ofilter,
|
|||
* @param graph_desc Graph description; an av_malloc()ed string, filtergraph
|
||||
* takes ownership of it.
|
||||
*/
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch);
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch,
|
||||
const OutputFilterOptions *opts);
|
||||
|
||||
void fg_free(FilterGraph **pfg);
|
||||
|
||||
|
|
@ -929,6 +965,15 @@ void opt_match_per_stream_int64(void *logctx, const SpecifierOptList *sol,
|
|||
void opt_match_per_stream_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStream *st, double *out);
|
||||
|
||||
void opt_match_per_stream_group_str(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, const char **out);
|
||||
void opt_match_per_stream_group_int(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int *out);
|
||||
void opt_match_per_stream_group_int64(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, int64_t *out);
|
||||
void opt_match_per_stream_group_dbl(void *logctx, const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg, double *out);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs);
|
||||
|
||||
int muxer_thread(void *arg);
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ typedef struct DemuxStream {
|
|||
int64_t lag;
|
||||
} DemuxStream;
|
||||
|
||||
typedef struct DemuxStreamGroup {
|
||||
InputStreamGroup istg;
|
||||
|
||||
// name used for logging
|
||||
char log_name[32];
|
||||
} DemuxStreamGroup;
|
||||
|
||||
typedef struct Demuxer {
|
||||
InputFile f;
|
||||
|
||||
|
|
@ -886,6 +893,16 @@ static void ist_free(InputStream **pist)
|
|||
av_freep(pist);
|
||||
}
|
||||
|
||||
static void istg_free(InputStreamGroup **pistg)
|
||||
{
|
||||
InputStreamGroup *istg = *pistg;
|
||||
|
||||
if (!istg)
|
||||
return;
|
||||
|
||||
av_freep(pistg);
|
||||
}
|
||||
|
||||
void ifile_close(InputFile **pf)
|
||||
{
|
||||
InputFile *f = *pf;
|
||||
|
|
@ -901,6 +918,10 @@ void ifile_close(InputFile **pf)
|
|||
ist_free(&f->streams[i]);
|
||||
av_freep(&f->streams);
|
||||
|
||||
for (int i = 0; i < f->nb_stream_groups; i++)
|
||||
istg_free(&f->stream_groups[i]);
|
||||
av_freep(&f->stream_groups);
|
||||
|
||||
avformat_close_input(&f->ctx);
|
||||
|
||||
av_packet_free(&d->pkt_heartbeat);
|
||||
|
|
@ -1586,6 +1607,139 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *input_stream_group_item_name(void *obj)
|
||||
{
|
||||
const DemuxStreamGroup *dsg = obj;
|
||||
|
||||
return dsg->log_name;
|
||||
}
|
||||
|
||||
static const AVClass input_stream_group_class = {
|
||||
.class_name = "InputStreamGroup",
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
.item_name = input_stream_group_item_name,
|
||||
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||
};
|
||||
|
||||
static DemuxStreamGroup *demux_stream_group_alloc(Demuxer *d, AVStreamGroup *stg)
|
||||
{
|
||||
InputFile *f = &d->f;
|
||||
DemuxStreamGroup *dsg;
|
||||
|
||||
dsg = allocate_array_elem(&f->stream_groups, sizeof(*dsg), &f->nb_stream_groups);
|
||||
if (!dsg)
|
||||
return NULL;
|
||||
|
||||
dsg->istg.stg = stg;
|
||||
dsg->istg.file = f;
|
||||
dsg->istg.index = stg->index;
|
||||
dsg->istg.class = &input_stream_group_class;
|
||||
|
||||
snprintf(dsg->log_name, sizeof(dsg->log_name), "istg#%d:%d/%s",
|
||||
d->f.index, stg->index, avformat_stream_group_name(stg->type));
|
||||
|
||||
return dsg;
|
||||
}
|
||||
|
||||
static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStreamGroup *istg)
|
||||
{
|
||||
InputFile *f = &d->f;
|
||||
AVFormatContext *ic = d->f.ctx;
|
||||
AVStreamGroup *stg = istg->stg;
|
||||
const AVStreamGroupTileGrid *tg = stg->params.tile_grid;
|
||||
OutputFilterOptions opts;
|
||||
AVBPrint bp;
|
||||
char *graph_str;
|
||||
int autorotate = 1;
|
||||
const char *apply_cropping = NULL;
|
||||
int ret;
|
||||
|
||||
if (tg->nb_tiles == 1)
|
||||
return 0;
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
|
||||
opt_match_per_stream_group_int(istg, &o->autorotate, ic, stg, &autorotate);
|
||||
if (autorotate)
|
||||
opts.flags |= OFILTER_FLAG_AUTOROTATE;
|
||||
|
||||
opts.flags |= OFILTER_FLAG_CROP;
|
||||
opt_match_per_stream_group_str(istg, &o->apply_cropping, ic, stg, &apply_cropping);
|
||||
if (apply_cropping) {
|
||||
char *p;
|
||||
int crop = strtol(apply_cropping, &p, 0);
|
||||
if (*p)
|
||||
return AVERROR(EINVAL);
|
||||
if (!crop)
|
||||
opts.flags &= ~OFILTER_FLAG_CROP;
|
||||
}
|
||||
|
||||
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
for (int i = 0; i < tg->nb_tiles; i++)
|
||||
av_bprintf(&bp, "[%d:g:%d:%d]", f->index, stg->index, tg->offsets[i].idx);
|
||||
av_bprintf(&bp, "xstack=inputs=%d:layout=", tg->nb_tiles);
|
||||
for (int i = 0; i < tg->nb_tiles - 1; i++)
|
||||
av_bprintf(&bp, "%d_%d|", tg->offsets[i].horizontal,
|
||||
tg->offsets[i].vertical);
|
||||
av_bprintf(&bp, "%d_%d:fill=0x%02X%02X%02X@0x%02X", tg->offsets[tg->nb_tiles - 1].horizontal,
|
||||
tg->offsets[tg->nb_tiles - 1].vertical,
|
||||
tg->background[0], tg->background[1],
|
||||
tg->background[2], tg->background[3]);
|
||||
av_bprintf(&bp, "[%d:g:%d]", f->index, stg->index);
|
||||
ret = av_bprint_finalize(&bp, &graph_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (tg->coded_width != tg->width || tg->coded_height != tg->height) {
|
||||
opts.crop_top = tg->vertical_offset;
|
||||
opts.crop_bottom = tg->coded_height - tg->height - tg->vertical_offset;
|
||||
opts.crop_left = tg->horizontal_offset;
|
||||
opts.crop_right = tg->coded_width - tg->width - tg->horizontal_offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tg->nb_coded_side_data; i++) {
|
||||
const AVPacketSideData *sd = &tg->coded_side_data[i];
|
||||
|
||||
ret = av_packet_side_data_to_frame(&opts.side_data, &opts.nb_side_data, sd, 0);
|
||||
if (ret < 0 && ret != AVERROR(EINVAL))
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fg_create(NULL, graph_str, d->sch, &opts);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
istg->fg = filtergraphs[nb_filtergraphs-1];
|
||||
istg->fg->is_internal = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int istg_add(const OptionsContext *o, Demuxer *d, AVStreamGroup *stg)
|
||||
{
|
||||
DemuxStreamGroup *dsg;
|
||||
InputStreamGroup *istg;
|
||||
int ret;
|
||||
|
||||
dsg = demux_stream_group_alloc(d, stg);
|
||||
if (!dsg)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
istg = &dsg->istg;
|
||||
|
||||
switch (stg->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID:
|
||||
ret = istg_parse_tile_grid(o, d, istg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_attachment(InputStream *ist, const char *filename)
|
||||
{
|
||||
AVStream *st = ist->st;
|
||||
|
|
@ -1954,6 +2108,13 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
|
|||
}
|
||||
}
|
||||
|
||||
/* Add all the stream groups from the given input file to the demuxer */
|
||||
for (int i = 0; i < ic->nb_stream_groups; i++) {
|
||||
ret = istg_add(o, d, ic->stream_groups[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* dump the file content */
|
||||
av_dump_format(ic, f->index, filename, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -205,19 +205,10 @@ int enc_open(void *opaque, const AVFrame *frame)
|
|||
av_assert0(frame->opaque_ref);
|
||||
fd = (FrameData*)frame->opaque_ref->data;
|
||||
|
||||
for (int i = 0; i < frame->nb_side_data; i++) {
|
||||
const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type);
|
||||
|
||||
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL))
|
||||
continue;
|
||||
|
||||
ret = av_frame_side_data_clone(&enc_ctx->decoded_side_data,
|
||||
&enc_ctx->nb_decoded_side_data,
|
||||
frame->side_data[i],
|
||||
AV_FRAME_SIDE_DATA_FLAG_UNIQUE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = clone_side_data(&enc_ctx->decoded_side_data, &enc_ctx->nb_decoded_side_data,
|
||||
fd->side_data, fd->nb_side_data, AV_FRAME_SIDE_DATA_FLAG_UNIQUE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ist)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ typedef struct InputFilterPriv {
|
|||
// used to hold submitted input
|
||||
AVFrame *frame;
|
||||
|
||||
// For inputs bound to a filtergraph output
|
||||
OutputFilter *ofilter_src;
|
||||
|
||||
// source data type: AVMEDIA_TYPE_SUBTITLE for sub2video,
|
||||
// same as type otherwise
|
||||
enum AVMediaType type_src;
|
||||
|
|
@ -190,6 +193,8 @@ typedef struct OutputFilterPriv {
|
|||
void *log_parent;
|
||||
char log_name[32];
|
||||
|
||||
int needed;
|
||||
|
||||
/* desired output stream properties */
|
||||
int format;
|
||||
int width, height;
|
||||
|
|
@ -199,6 +204,11 @@ typedef struct OutputFilterPriv {
|
|||
enum AVColorRange color_range;
|
||||
enum AVAlphaMode alpha_mode;
|
||||
|
||||
unsigned crop_top;
|
||||
unsigned crop_bottom;
|
||||
unsigned crop_left;
|
||||
unsigned crop_right;
|
||||
|
||||
AVFrameSideData **side_data;
|
||||
int nb_side_data;
|
||||
|
||||
|
|
@ -223,6 +233,8 @@ typedef struct OutputFilterPriv {
|
|||
const enum AVColorRange *color_ranges;
|
||||
const enum AVAlphaMode *alpha_modes;
|
||||
|
||||
int32_t displaymatrix[9];
|
||||
|
||||
AVRational enc_timebase;
|
||||
int64_t trim_start_us;
|
||||
int64_t trim_duration_us;
|
||||
|
|
@ -810,10 +822,10 @@ int ofilter_bind_enc(OutputFilter *ofilter, unsigned sched_idx_enc,
|
|||
av_assert0(!opts->enc ||
|
||||
ofilter->type == opts->enc->type);
|
||||
|
||||
ofilter->bound = 1;
|
||||
ofp->needed = ofilter->bound = 1;
|
||||
av_freep(&ofilter->linklabel);
|
||||
|
||||
ofp->flags = opts->flags;
|
||||
ofp->flags |= opts->flags;
|
||||
ofp->ts_offset = opts->ts_offset;
|
||||
ofp->enc_timebase = opts->output_tb;
|
||||
|
||||
|
|
@ -921,13 +933,15 @@ static int ofilter_bind_ifilter(OutputFilter *ofilter, InputFilterPriv *ifp,
|
|||
av_assert0(!ofilter->bound);
|
||||
av_assert0(ofilter->type == ifp->ifilter.type);
|
||||
|
||||
ofilter->bound = 1;
|
||||
ofp->needed = ofilter->bound = 1;
|
||||
av_freep(&ofilter->linklabel);
|
||||
|
||||
ofilter->output_name = av_strdup(opts->name);
|
||||
if (!ofilter->output_name)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
ifp->ofilter_src = ofilter;
|
||||
|
||||
av_strlcatf(ofp->log_name, sizeof(ofp->log_name), "->%s", ofilter->output_name);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1071,7 +1085,8 @@ static const AVClass fg_class = {
|
|||
.category = AV_CLASS_CATEGORY_FILTER,
|
||||
};
|
||||
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
|
||||
int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch,
|
||||
const OutputFilterOptions *opts)
|
||||
{
|
||||
FilterGraphPriv *fgp;
|
||||
FilterGraph *fg;
|
||||
|
|
@ -1168,11 +1183,13 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
|
|||
const enum AVMediaType type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
|
||||
cur->pad_idx);
|
||||
OutputFilter *const ofilter = ofilter_alloc(fg, type);
|
||||
OutputFilterPriv *ofp;
|
||||
|
||||
if (!ofilter) {
|
||||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
ofp = ofp_from_ofilter(ofilter);
|
||||
|
||||
ofilter->linklabel = cur->name;
|
||||
cur->name = NULL;
|
||||
|
|
@ -1182,6 +1199,25 @@ int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch)
|
|||
ret = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// opts should only be needed in this function to fill fields from filtergraphs
|
||||
// whose output is meant to be treated as if it was stream, e.g. merged HEIF
|
||||
// tile groups.
|
||||
if (opts) {
|
||||
ofp->flags = opts->flags;
|
||||
ofp->side_data = opts->side_data;
|
||||
ofp->nb_side_data = opts->nb_side_data;
|
||||
|
||||
ofp->crop_top = opts->crop_top;
|
||||
ofp->crop_bottom = opts->crop_bottom;
|
||||
ofp->crop_left = opts->crop_left;
|
||||
ofp->crop_right = opts->crop_right;
|
||||
|
||||
const AVFrameSideData *sd = av_frame_side_data_get(ofp->side_data, ofp->nb_side_data,
|
||||
AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
if (sd)
|
||||
memcpy(ofp->displaymatrix, sd->data, sizeof(ofp->displaymatrix));
|
||||
}
|
||||
}
|
||||
|
||||
if (!fg->nb_outputs) {
|
||||
|
|
@ -1218,7 +1254,7 @@ int fg_create_simple(FilterGraph **pfg,
|
|||
FilterGraphPriv *fgp;
|
||||
int ret;
|
||||
|
||||
ret = fg_create(pfg, graph_desc, sch);
|
||||
ret = fg_create(pfg, graph_desc, sch, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
fg = *pfg;
|
||||
|
|
@ -1259,7 +1295,7 @@ int fg_create_simple(FilterGraph **pfg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
|
||||
static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter, int commit)
|
||||
{
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||
InputStream *ist = NULL;
|
||||
|
|
@ -1310,15 +1346,20 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
|
|||
|
||||
if (!ofilter->bound && ofilter->linklabel &&
|
||||
!strcmp(ofilter->linklabel, ifilter->linklabel)) {
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to filtergraph output %d:%d\n",
|
||||
ifilter->linklabel, i, j);
|
||||
if (commit) {
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to filtergraph output %d:%d\n",
|
||||
ifilter->linklabel, i, j);
|
||||
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0)
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n",
|
||||
ifilter->linklabel);
|
||||
return ret;
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %s\n",
|
||||
ifilter->linklabel);
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
ofp_from_ofilter(ofilter)->needed = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,10 +1407,38 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
|
|||
}
|
||||
ist = input_files[file_idx]->streams[st->index];
|
||||
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to input stream %d:%d\n",
|
||||
ifilter->linklabel, ist->file->index, ist->index);
|
||||
if (commit)
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding input with label '%s' to input stream %d:%d\n",
|
||||
ifilter->linklabel, ist->file->index, ist->index);
|
||||
} else {
|
||||
// try finding an unbound filtergraph output
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
FilterGraph *fg_src = filtergraphs[i];
|
||||
|
||||
if (fg == fg_src)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < fg_src->nb_outputs; j++) {
|
||||
OutputFilter *ofilter = fg_src->outputs[j];
|
||||
|
||||
if (!ofilter->bound) {
|
||||
if (commit) {
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled filtergraph input to filtergraph output %d:%d\n", i, j);
|
||||
|
||||
ret = ifilter_bind_fg(ifp, fg_src, j);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR, "Error binding filtergraph input %d:%d\n", i, j);
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
ofp_from_ofilter(ofilter)->needed = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ist = ist_find_unused(type);
|
||||
if (!ist) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
|
|
@ -1379,24 +1448,27 @@ static int fg_complex_bind_input(FilterGraph *fg, InputFilter *ifilter)
|
|||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled input %d to input stream %d:%d\n",
|
||||
ifilter->index, ist->file->index, ist->index);
|
||||
if (commit)
|
||||
av_log(fg, AV_LOG_VERBOSE,
|
||||
"Binding unlabeled input %d to input stream %d:%d\n",
|
||||
ifilter->index, ist->file->index, ist->index);
|
||||
}
|
||||
av_assert0(ist);
|
||||
|
||||
ret = ifilter_bind_ist(ifilter, ist, &vs);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR,
|
||||
"Error binding an input stream to complex filtergraph input %s.\n",
|
||||
ifilter->name);
|
||||
return ret;
|
||||
if (commit) {
|
||||
ret = ifilter_bind_ist(ifilter, ist, &vs);
|
||||
if (ret < 0) {
|
||||
av_log(fg, AV_LOG_ERROR,
|
||||
"Error binding an input stream to complex filtergraph input %s.\n",
|
||||
ifilter->name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bind_inputs(FilterGraph *fg)
|
||||
static int bind_inputs(FilterGraph *fg, int commit)
|
||||
{
|
||||
// bind filtergraph inputs to input streams or other filtergraphs
|
||||
for (int i = 0; i < fg->nb_inputs; i++) {
|
||||
|
|
@ -1406,7 +1478,7 @@ static int bind_inputs(FilterGraph *fg)
|
|||
if (ifp->bound)
|
||||
continue;
|
||||
|
||||
ret = fg_complex_bind_input(fg, &ifp->ifilter);
|
||||
ret = fg_complex_bind_input(fg, &ifp->ifilter, commit);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1419,27 +1491,49 @@ int fg_finalise_bindings(void)
|
|||
int ret;
|
||||
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
ret = bind_inputs(filtergraphs[i]);
|
||||
ret = bind_inputs(filtergraphs[i], 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// check that all outputs were bound
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
for (int i = nb_filtergraphs - 1; i >= 0; i--) {
|
||||
FilterGraph *fg = filtergraphs[i];
|
||||
FilterGraphPriv *fgp = fgp_from_fg(filtergraphs[i]);
|
||||
|
||||
for (int j = 0; j < fg->nb_outputs; j++) {
|
||||
OutputFilter *output = fg->outputs[j];
|
||||
if (!output->bound) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
"Filter '%s' has output %d (%s) unconnected\n",
|
||||
if (!ofp_from_ofilter(output)->needed) {
|
||||
if (!fg->is_internal) {
|
||||
av_log(fg, AV_LOG_FATAL,
|
||||
"Filter '%s' has output %d (%s) unconnected\n",
|
||||
output->name, j,
|
||||
output->linklabel ? (const char *)output->linklabel : "unlabeled");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
av_log(fg, AV_LOG_DEBUG,
|
||||
"Internal filter '%s' has output %d (%s) unconnected. Removing graph\n",
|
||||
output->name, j,
|
||||
output->linklabel ? (const char *)output->linklabel : "unlabeled");
|
||||
return AVERROR(EINVAL);
|
||||
sch_remove_filtergraph(fgp->sch, fgp->sch_idx);
|
||||
fg_free(&filtergraphs[i]);
|
||||
nb_filtergraphs--;
|
||||
if (nb_filtergraphs > 0)
|
||||
memmove(&filtergraphs[i],
|
||||
&filtergraphs[i + 1],
|
||||
(nb_filtergraphs - i) * sizeof(*filtergraphs));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < nb_filtergraphs; i++) {
|
||||
ret = bind_inputs(filtergraphs[i], 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1538,6 +1632,53 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ofp->flags & OFILTER_FLAG_CROP) {
|
||||
char crop_buf[64];
|
||||
snprintf(crop_buf, sizeof(crop_buf), "w=iw-%u-%u:h=ih-%u-%u:x=%u:y=%u",
|
||||
ofp->crop_left, ofp->crop_right,
|
||||
ofp->crop_top, ofp->crop_bottom,
|
||||
ofp->crop_left, ofp->crop_top);
|
||||
ret = insert_filter(&last_filter, &pad_idx, "crop", crop_buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ofp->flags & OFILTER_FLAG_AUTOROTATE) {
|
||||
int32_t *displaymatrix = ofp->displaymatrix;
|
||||
double theta;
|
||||
|
||||
theta = get_rotation(displaymatrix);
|
||||
|
||||
if (fabs(theta - 90) < 1.0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "transpose",
|
||||
displaymatrix[3] > 0 ? "cclock_flip" : "clock");
|
||||
} else if (fabs(theta - 180) < 1.0) {
|
||||
if (displaymatrix[0] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (displaymatrix[4] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
|
||||
}
|
||||
} else if (fabs(theta - 270) < 1.0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "transpose",
|
||||
displaymatrix[3] < 0 ? "clock_flip" : "cclock");
|
||||
} else if (fabs(theta) > 1.0) {
|
||||
char rotate_buf[64];
|
||||
snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
|
||||
ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
|
||||
} else if (fabs(theta) < 1.0) {
|
||||
if (displaymatrix && displaymatrix[4] < 0) {
|
||||
ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
|
||||
}
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_frame_side_data_remove(&ofp->side_data, &ofp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
|
||||
}
|
||||
|
||||
if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) {
|
||||
char args[255];
|
||||
AVFilterContext *filter;
|
||||
|
|
@ -2035,12 +2176,11 @@ static int configure_filtergraph(FilterGraph *fg, FilterGraphThread *fgt)
|
|||
ret = av_buffersink_get_ch_layout(sink, &ofp->ch_layout);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
|
||||
sd = av_buffersink_get_side_data(sink, &nb_sd);
|
||||
if (nb_sd)
|
||||
for (int j = 0; j < nb_sd; j++) {
|
||||
ret = av_frame_side_data_clone(&ofp->side_data, &ofp->nb_side_data,
|
||||
sd[j], 0);
|
||||
sd[j], AV_FRAME_SIDE_DATA_FLAG_REPLACE);
|
||||
if (ret < 0) {
|
||||
av_frame_side_data_free(&ofp->side_data, &ofp->nb_side_data);
|
||||
goto fail;
|
||||
|
|
@ -2124,7 +2264,8 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
|||
for (int i = 0; i < frame->nb_side_data; i++) {
|
||||
const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type);
|
||||
|
||||
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL))
|
||||
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL) ||
|
||||
frame->side_data[i]->type == AV_FRAME_DATA_DISPLAYMATRIX)
|
||||
continue;
|
||||
|
||||
ret = av_frame_side_data_clone(&ifp->side_data,
|
||||
|
|
@ -2155,6 +2296,27 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ifilter_parameters_from_ofilter(InputFilter *ifilter, OutputFilter *ofilter)
|
||||
{
|
||||
const OutputFilterPriv *ofp = ofp_from_ofilter(ofilter);
|
||||
InputFilterPriv *ifp = ifp_from_ifilter(ifilter);
|
||||
|
||||
if (!ifp->opts.framerate.num) {
|
||||
ifp->opts.framerate = ofp->fps.framerate;
|
||||
if (ifp->opts.framerate.num > 0 && ifp->opts.framerate.den > 0)
|
||||
ifp->opts.flags |= IFILTER_FLAG_CFR;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ofp->nb_side_data; i++) {
|
||||
int ret = av_frame_side_data_clone(&ifp->side_data, &ifp->nb_side_data,
|
||||
ofp->side_data[i], AV_FRAME_SIDE_DATA_FLAG_REPLACE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filtergraph_is_simple(const FilterGraph *fg)
|
||||
{
|
||||
const FilterGraphPriv *fgp = cfgp_from_cfg(fg);
|
||||
|
|
@ -2476,16 +2638,17 @@ static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
av_frame_side_data_free(&frame->side_data, &frame->nb_side_data);
|
||||
ret = clone_side_data(&frame->side_data, &frame->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fd = frame_data(frame);
|
||||
if (!fd)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fd->frame_rate_filter = ofp->fps.framerate;
|
||||
|
||||
av_assert0(!frame->buf[0]);
|
||||
|
|
@ -2640,6 +2803,14 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt,
|
|||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
av_frame_side_data_free(&fd->side_data, &fd->nb_side_data);
|
||||
if (!fgt->got_frame) {
|
||||
ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
|
||||
ofp->side_data, ofp->nb_side_data, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
fd->wallclock[LATENCY_PROBE_FILTER_POST] = av_gettime_relative();
|
||||
|
||||
// only use bits_per_raw_sample passed through from the decoder
|
||||
|
|
@ -2935,6 +3106,14 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
|
|||
ret = ifilter_parameters_from_frame(ifilter, frame);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Inputs bound to a filtergraph output will have some fields unset.
|
||||
* Handle them here */
|
||||
if (ifp->ofilter_src) {
|
||||
ret = ifilter_parameters_from_ofilter(ifilter, ifp->ofilter_src);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* (re)init the graph if possible, otherwise buffer the frame and return */
|
||||
|
|
|
|||
|
|
@ -1598,6 +1598,7 @@ fail:
|
|||
static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
||||
{
|
||||
AVFormatContext *oc = mux->fc;
|
||||
InputStreamGroup *best_istg = NULL;
|
||||
InputStream *best_ist = NULL;
|
||||
int64_t best_score = 0;
|
||||
int qcr;
|
||||
|
|
@ -1609,8 +1610,41 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
|||
qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
|
||||
for (int j = 0; j < nb_input_files; j++) {
|
||||
InputFile *ifile = input_files[j];
|
||||
InputStreamGroup *file_best_istg = NULL;
|
||||
InputStream *file_best_ist = NULL;
|
||||
int64_t file_best_score = 0;
|
||||
for (int i = 0; i < ifile->nb_stream_groups; i++) {
|
||||
InputStreamGroup *istg = ifile->stream_groups[i];
|
||||
int64_t score = 0;
|
||||
|
||||
if (!istg->fg)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < istg->stg->nb_streams; j++) {
|
||||
AVStream *st = istg->stg->streams[j];
|
||||
|
||||
if (st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) {
|
||||
score = 100000000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (istg->stg->type) {
|
||||
case AV_STREAM_GROUP_PARAMS_TILE_GRID: {
|
||||
const AVStreamGroupTileGrid *tg = istg->stg->params.tile_grid;
|
||||
score += tg->width * (int64_t)tg->height
|
||||
+ 5000000*!!(istg->stg->disposition & AV_DISPOSITION_DEFAULT);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (score > file_best_score) {
|
||||
file_best_score = score;
|
||||
file_best_istg = istg;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ifile->nb_streams; i++) {
|
||||
InputStream *ist = ifile->streams[i];
|
||||
int64_t score;
|
||||
|
|
@ -1630,6 +1664,15 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
|||
continue;
|
||||
file_best_score = score;
|
||||
file_best_ist = ist;
|
||||
file_best_istg = NULL;
|
||||
}
|
||||
}
|
||||
if (file_best_istg) {
|
||||
file_best_score -= 5000000*!!(file_best_istg->stg->disposition & AV_DISPOSITION_DEFAULT);
|
||||
if (file_best_score > best_score) {
|
||||
best_score = file_best_score;
|
||||
best_istg = file_best_istg;
|
||||
best_ist = NULL;
|
||||
}
|
||||
}
|
||||
if (file_best_ist) {
|
||||
|
|
@ -1639,9 +1682,19 @@ static int map_auto_video(Muxer *mux, const OptionsContext *o)
|
|||
if (file_best_score > best_score) {
|
||||
best_score = file_best_score;
|
||||
best_ist = file_best_ist;
|
||||
best_istg = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_istg) {
|
||||
FilterGraph *fg = best_istg->fg;
|
||||
OutputFilter *ofilter = fg->outputs[0];
|
||||
|
||||
av_assert0(fg->nb_outputs == 1);
|
||||
av_log(mux, AV_LOG_VERBOSE, "Creating output stream from stream group derived complex filtergraph %d.\n", fg->index);
|
||||
|
||||
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, NULL, ofilter, NULL, NULL);
|
||||
}
|
||||
if (best_ist)
|
||||
return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,70 @@ OPT_MATCH_PER_STREAM(int, int, OPT_TYPE_INT, i);
|
|||
OPT_MATCH_PER_STREAM(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
static unsigned opt_match_per_stream_group(void *logctx, enum OptionType type,
|
||||
const SpecifierOptList *sol,
|
||||
AVFormatContext *fc, AVStreamGroup *stg)
|
||||
{
|
||||
int matches = 0, match_idx = -1;
|
||||
|
||||
av_assert0((type == sol->type) || !sol->nb_opt);
|
||||
|
||||
for (int i = 0; i < sol->nb_opt; i++) {
|
||||
const StreamSpecifier *ss = &sol->opt[i].stream_spec;
|
||||
|
||||
if (stream_group_specifier_match(ss, fc, stg, logctx)) {
|
||||
match_idx = i;
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches > 1 && sol->opt_canon) {
|
||||
const SpecifierOpt *so = &sol->opt[match_idx];
|
||||
const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";
|
||||
|
||||
char namestr[128] = "";
|
||||
char optval_buf[32];
|
||||
const char *optval = optval_buf;
|
||||
|
||||
snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name);
|
||||
if (sol->opt_canon->flags & OPT_HAS_ALT) {
|
||||
const char * const *names_alt = sol->opt_canon->u1.names_alt;
|
||||
for (int i = 0; names_alt[i]; i++)
|
||||
av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]);
|
||||
}
|
||||
|
||||
switch (sol->type) {
|
||||
case OPT_TYPE_STRING: optval = so->u.str; break;
|
||||
case OPT_TYPE_INT: snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i); break;
|
||||
case OPT_TYPE_INT64: snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break;
|
||||
case OPT_TYPE_FLOAT: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f); break;
|
||||
case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl); break;
|
||||
default: av_assert0(0);
|
||||
}
|
||||
|
||||
av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for "
|
||||
"stream group %d, only the last option '-%s%s%s %s' will be used.\n",
|
||||
namestr, stg->index, sol->opt_canon->name, spec[0] ? ":" : "",
|
||||
spec, optval);
|
||||
}
|
||||
|
||||
return match_idx + 1;
|
||||
}
|
||||
|
||||
#define OPT_MATCH_PER_STREAM_GROUP(name, type, opt_type, m) \
|
||||
void opt_match_per_stream_group_ ## name(void *logctx, const SpecifierOptList *sol, \
|
||||
AVFormatContext *fc, AVStreamGroup *stg, type *out) \
|
||||
{ \
|
||||
unsigned ret = opt_match_per_stream_group(logctx, opt_type, sol, fc, stg); \
|
||||
if (ret > 0) \
|
||||
*out = sol->opt[ret - 1].u.m; \
|
||||
}
|
||||
|
||||
OPT_MATCH_PER_STREAM_GROUP(str, const char *, OPT_TYPE_STRING, str);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int, int, OPT_TYPE_INT, i);
|
||||
OPT_MATCH_PER_STREAM_GROUP(int64, int64_t, OPT_TYPE_INT64, i64);
|
||||
OPT_MATCH_PER_STREAM_GROUP(dbl, double, OPT_TYPE_DOUBLE, dbl);
|
||||
|
||||
int view_specifier_parse(const char **pspec, ViewSpecifier *vs)
|
||||
{
|
||||
const char *spec = *pspec;
|
||||
|
|
@ -504,8 +568,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
|||
}
|
||||
|
||||
if (arg[0] == '[') {
|
||||
ViewSpecifier vs;
|
||||
/* this mapping refers to lavfi output */
|
||||
const char *c = arg + 1;
|
||||
char *endptr;
|
||||
|
||||
ret = GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
|
||||
if (ret < 0)
|
||||
|
|
@ -518,6 +584,27 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
|||
ret = AVERROR(EINVAL);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
arg++;
|
||||
|
||||
m->group_index = -1;
|
||||
file_idx = strtol(arg, &endptr, 0);
|
||||
if (file_idx >= nb_input_files || file_idx < 0)
|
||||
goto end;
|
||||
|
||||
arg = endptr;
|
||||
ret = stream_specifier_parse(&ss, *arg == ':' ? arg + 1 : arg, 1, NULL);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
arg = ss.remainder ? ss.remainder : "";
|
||||
ret = view_specifier_parse(&arg, &vs);
|
||||
if (ret < 0 || (*arg && strcmp(arg, "]")))
|
||||
goto end;
|
||||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = ss.idx;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
} else {
|
||||
ViewSpecifier vs;
|
||||
char *endptr;
|
||||
|
|
@ -583,6 +670,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
|||
|
||||
m->file_index = file_idx;
|
||||
m->stream_index = i;
|
||||
m->group_index = ss.stream_list == STREAM_LIST_GROUP_IDX ? ss.list_id : -1;
|
||||
m->vs = vs;
|
||||
}
|
||||
}
|
||||
|
|
@ -602,6 +690,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
end:
|
||||
ret = 0;
|
||||
fail:
|
||||
stream_specifier_uninit(&ss);
|
||||
|
|
@ -1407,7 +1496,7 @@ int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch)
|
|||
|
||||
/* create complex filtergraphs */
|
||||
for (int i = 0; i < go.nb_filtergraphs; i++) {
|
||||
ret = fg_create(NULL, go.filtergraphs[i], sch);
|
||||
ret = fg_create(NULL, go.filtergraphs[i], sch, NULL);
|
||||
go.filtergraphs[i] = NULL;
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -405,6 +405,9 @@ static int task_start(SchTask *task)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!task->parent)
|
||||
return 0;
|
||||
|
||||
av_log(task->func_arg, AV_LOG_VERBOSE, "Starting thread...\n");
|
||||
|
||||
av_assert0(!task->thread_running);
|
||||
|
|
@ -454,6 +457,23 @@ static int64_t trailing_dts(const Scheduler *sch, int count_finished)
|
|||
return min_dts == INT64_MAX ? AV_NOPTS_VALUE : min_dts;
|
||||
}
|
||||
|
||||
void sch_remove_filtergraph(Scheduler *sch, int idx)
|
||||
{
|
||||
SchFilterGraph *fg = &sch->filters[idx];
|
||||
|
||||
av_assert0(!fg->task.thread_running);
|
||||
memset(&fg->task, 0, sizeof(fg->task));
|
||||
|
||||
tq_free(&fg->queue);
|
||||
|
||||
av_freep(&fg->inputs);
|
||||
fg->nb_inputs = 0;
|
||||
av_freep(&fg->outputs);
|
||||
fg->nb_outputs = 0;
|
||||
|
||||
fg->task_exited = 1;
|
||||
}
|
||||
|
||||
void sch_free(Scheduler **psch)
|
||||
{
|
||||
Scheduler *sch = *psch;
|
||||
|
|
@ -2630,6 +2650,9 @@ static int task_stop(Scheduler *sch, SchTask *task)
|
|||
int ret;
|
||||
void *thread_ret;
|
||||
|
||||
if (!task->parent)
|
||||
return 0;
|
||||
|
||||
if (!task->thread_running)
|
||||
return task_cleanup(sch, task->node);
|
||||
|
||||
|
|
|
|||
|
|
@ -205,6 +205,8 @@ int sch_add_dec_output(Scheduler *sch, unsigned dec_idx);
|
|||
int sch_add_filtergraph(Scheduler *sch, unsigned nb_inputs, unsigned nb_outputs,
|
||||
SchThreadFunc func, void *ctx);
|
||||
|
||||
void sch_remove_filtergraph(Scheduler *sch, int idx);
|
||||
|
||||
/**
|
||||
* Add a muxer to the scheduler.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -815,3 +815,53 @@ int avcodec_get_supported_config(const AVCodecContext *avctx, const AVCodec *cod
|
|||
return ff_default_get_supported_config(avctx, codec, config, flags, out, out_num);
|
||||
}
|
||||
}
|
||||
|
||||
int av_packet_side_data_from_frame(AVPacketSideData **psd, int *pnb_sd,
|
||||
const AVFrameSideData *src, unsigned int flags)
|
||||
{
|
||||
AVPacketSideData *sd = NULL;
|
||||
|
||||
for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) {
|
||||
if (ff_sd_global_map[j].frame != src->type)
|
||||
continue;
|
||||
|
||||
sd = av_packet_side_data_new(psd, pnb_sd, ff_sd_global_map[j].packet,
|
||||
src->size, 0);
|
||||
|
||||
if (!sd)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
memcpy(sd->data, src->data, src->size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sd)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int av_packet_side_data_to_frame(AVFrameSideData ***psd, int *pnb_sd,
|
||||
const AVPacketSideData *src, unsigned int flags)
|
||||
{
|
||||
AVFrameSideData *sd = NULL;
|
||||
|
||||
for (unsigned j = 0; ff_sd_global_map[j].packet < AV_PKT_DATA_NB; j++) {
|
||||
if (ff_sd_global_map[j].packet != src->type)
|
||||
continue;
|
||||
|
||||
sd = av_frame_side_data_new(psd, pnb_sd, ff_sd_global_map[j].frame,
|
||||
src->size, flags);
|
||||
|
||||
if (!sd)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
memcpy(sd->data, src->data, src->size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!sd)
|
||||
return AVERROR(EINVAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ typedef struct HFParam {
|
|||
* Optimized fixed codebook excitation parameters
|
||||
*/
|
||||
typedef struct FCBParam {
|
||||
int min_err;
|
||||
int64_t min_err;
|
||||
int amp_index;
|
||||
int grid_index;
|
||||
int dirac_train;
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,7 @@ static void fcb_search(G723_1_ChannelContext *p, int16_t *impulse_resp,
|
|||
int pulse_cnt = pulses[index];
|
||||
int i;
|
||||
|
||||
optim.min_err = 1 << 30;
|
||||
optim.min_err = 1LL << 31;
|
||||
get_fcb_param(&optim, impulse_resp, buf, pulse_cnt, SUBFRAME_LEN);
|
||||
|
||||
if (p->pitch_lag[index >> 1] < SUBFRAME_LEN - 2) {
|
||||
|
|
|
|||
|
|
@ -238,7 +238,6 @@ int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx,
|
|||
static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx,
|
||||
PTLCommon *ptl)
|
||||
{
|
||||
const char *profile_name = NULL;
|
||||
int i;
|
||||
|
||||
if (get_bits_left(gb) < 2+1+5 + 32 + 4 + 43 + 1)
|
||||
|
|
@ -249,14 +248,15 @@ static int decode_profile_tier_level(GetBitContext *gb, AVCodecContext *avctx,
|
|||
ptl->profile_idc = get_bits(gb, 5);
|
||||
|
||||
#if !CONFIG_SMALL
|
||||
const char *profile_name = NULL;
|
||||
for (int i = 0; ff_hevc_profiles[i].profile != AV_PROFILE_UNKNOWN; i++)
|
||||
if (ff_hevc_profiles[i].profile == ptl->profile_idc) {
|
||||
profile_name = ff_hevc_profiles[i].name;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
av_log(avctx, profile_name ? AV_LOG_DEBUG : AV_LOG_WARNING,
|
||||
"%s profile bitstream\n", profile_name ? profile_name : "Unknown");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
ptl->profile_compatibility_flag[i] = get_bits1(gb);
|
||||
|
|
|
|||
|
|
@ -489,6 +489,36 @@ void av_packet_side_data_remove(AVPacketSideData *sd, int *nb_sd,
|
|||
*/
|
||||
void av_packet_side_data_free(AVPacketSideData **sd, int *nb_sd);
|
||||
|
||||
struct AVFrameSideData;
|
||||
|
||||
/**
|
||||
* Add a new packet side data entry to an array based on existing frame
|
||||
* side data, if a matching type exists for packet side data.
|
||||
*
|
||||
* @param flags Currently unused. Must be 0.
|
||||
* @retval >= 0 Success
|
||||
* @retval AVERROR(EINVAL) The frame side data type does not have a matching
|
||||
* packet side data type.
|
||||
* @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or
|
||||
* similar.
|
||||
*/
|
||||
int av_packet_side_data_from_frame(AVPacketSideData **sd, int *nb_sd,
|
||||
const struct AVFrameSideData *src, unsigned int flags);
|
||||
/**
|
||||
* Add a new frame side data entry to an array based on existing packet
|
||||
* side data, if a matching type exists for frame side data.
|
||||
*
|
||||
* @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags,
|
||||
* or 0.
|
||||
* @retval >= 0 Success
|
||||
* @retval AVERROR(EINVAL) The packet side data type does not have a matching
|
||||
* frame side data type.
|
||||
* @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or
|
||||
* similar.
|
||||
*/
|
||||
int av_packet_side_data_to_frame(struct AVFrameSideData ***sd, int *nb_sd,
|
||||
const AVPacketSideData *src, unsigned int flags);
|
||||
|
||||
const char *av_packet_side_data_name(enum AVPacketSideDataType type);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -334,6 +334,9 @@ static int decode_frame(AVCodecContext *avctx,
|
|||
DECLARE_ALIGNED(32, uint8_t, qmat)[64];
|
||||
memset(qmat, 1, 64);
|
||||
|
||||
if (avctx->skip_frame >= AVDISCARD_ALL)
|
||||
return avpkt->size;
|
||||
|
||||
switch (avctx->codec_tag) {
|
||||
case 0:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ typedef int (*rv40_loop_filter_strength_func)(uint8_t *src, ptrdiff_t stride,
|
|||
int *p1, int *q1);
|
||||
|
||||
typedef struct RV34DSPContext {
|
||||
qpel_mc_func put_pixels_tab[4][16];
|
||||
qpel_mc_func avg_pixels_tab[4][16];
|
||||
qpel_mc_func put_pixels_tab[2][16];
|
||||
qpel_mc_func avg_pixels_tab[2][16];
|
||||
h264_chroma_mc_func put_chroma_pixels_tab[3];
|
||||
h264_chroma_mc_func avg_chroma_pixels_tab[3];
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "version_major.h"
|
||||
|
||||
#define LIBAVCODEC_VERSION_MINOR 16
|
||||
#define LIBAVCODEC_VERSION_MINOR 17
|
||||
#define LIBAVCODEC_VERSION_MICRO 100
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
|
|
|
|||
|
|
@ -527,7 +527,7 @@ int ff_vlc_init_multi_from_lengths(VLC *vlc, VLC_MULTI *multi, int nb_bits, int
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
multi->table = av_malloc(sizeof(*multi->table) << nb_bits);
|
||||
multi->table = av_mallocz(sizeof(*multi->table) << nb_bits);
|
||||
if (!multi->table)
|
||||
goto fail;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void ff_hevc_idct_ ## W ## _dc_8_ ## opt(int16_t *coeffs); \
|
|||
void ff_hevc_idct_ ## W ## _dc_10_ ## opt(int16_t *coeffs); \
|
||||
void ff_hevc_idct_ ## W ## _dc_12_ ## opt(int16_t *coeffs)
|
||||
|
||||
IDCT_DC_FUNCS(4x4, mmxext);
|
||||
IDCT_DC_FUNCS(4x4, sse2);
|
||||
IDCT_DC_FUNCS(8x8, sse2);
|
||||
IDCT_DC_FUNCS(16x16, sse2);
|
||||
IDCT_DC_FUNCS(32x32, sse2);
|
||||
|
|
@ -816,8 +816,6 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
|
||||
if (bit_depth == 8) {
|
||||
if (EXTERNAL_MMXEXT(cpu_flags)) {
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_mmxext;
|
||||
|
||||
c->add_residual[0] = ff_hevc_add_residual_4_8_mmxext;
|
||||
}
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
|
|
@ -832,6 +830,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
}
|
||||
SAO_BAND_INIT(8, sse2);
|
||||
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_sse2;
|
||||
c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_sse2;
|
||||
c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_sse2;
|
||||
c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_sse2;
|
||||
|
|
@ -998,7 +997,6 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
} else if (bit_depth == 10) {
|
||||
if (EXTERNAL_MMXEXT(cpu_flags)) {
|
||||
c->add_residual[0] = ff_hevc_add_residual_4_10_mmxext;
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_mmxext;
|
||||
}
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_sse2;
|
||||
|
|
@ -1013,6 +1011,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
SAO_BAND_INIT(10, sse2);
|
||||
SAO_EDGE_INIT(10, sse2);
|
||||
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_sse2;
|
||||
c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_sse2;
|
||||
c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_sse2;
|
||||
c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_sse2;
|
||||
|
|
@ -1218,9 +1217,6 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
}
|
||||
#endif /* HAVE_AVX2_EXTERNAL */
|
||||
} else if (bit_depth == 12) {
|
||||
if (EXTERNAL_MMXEXT(cpu_flags)) {
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_mmxext;
|
||||
}
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_sse2;
|
||||
c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_sse2;
|
||||
|
|
@ -1231,6 +1227,7 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
|
|||
SAO_BAND_INIT(12, sse2);
|
||||
SAO_EDGE_INIT(12, sse2);
|
||||
|
||||
c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_sse2;
|
||||
c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_sse2;
|
||||
c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_sse2;
|
||||
c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_sse2;
|
||||
|
|
|
|||
|
|
@ -273,16 +273,11 @@ cglobal hevc_idct_%1x%1_dc_%2, 1, 2, 1, coeff, tmp
|
|||
sar tmpd, (15 - %2)
|
||||
movd m0, tmpd
|
||||
SPLATW m0, xm0
|
||||
mova [coeffq+mmsize*0], m0
|
||||
mova [coeffq+mmsize*1], m0
|
||||
mova [coeffq+mmsize*2], m0
|
||||
mova [coeffq+mmsize*3], m0
|
||||
%if mmsize == 16
|
||||
mova [coeffq+mmsize*4], m0
|
||||
mova [coeffq+mmsize*5], m0
|
||||
mova [coeffq+mmsize*6], m0
|
||||
mova [coeffq+mmsize*7], m0
|
||||
%endif
|
||||
%assign %%offset 0
|
||||
%rep 2*%1*%1/mmsize
|
||||
mova [coeffq+%%offset], m0
|
||||
%assign %%offset %%offset+mmsize
|
||||
%endrep
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
|
|
@ -809,10 +804,8 @@ cglobal hevc_idct_32x32_%1, 1, 6, 16, 256, coeffs
|
|||
%endmacro
|
||||
|
||||
%macro INIT_IDCT_DC 1
|
||||
INIT_MMX mmxext
|
||||
IDCT_DC_NL 4, %1
|
||||
|
||||
INIT_XMM sse2
|
||||
IDCT_DC_NL 4, %1
|
||||
IDCT_DC_NL 8, %1
|
||||
IDCT_DC 16, 4, %1
|
||||
IDCT_DC 32, 16, %1
|
||||
|
|
|
|||
|
|
@ -1650,7 +1650,7 @@ static const AVOption libplacebo_options[] = {
|
|||
{"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, .unit = "range"},
|
||||
{"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, .unit = "range"},
|
||||
|
||||
{"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_NB-1, DYNAMIC, .unit = "color_primaries"},
|
||||
{"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_EXT_NB-1, DYNAMIC, .unit = "color_primaries"},
|
||||
{"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
|
||||
{"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
|
||||
{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
|
||||
|
|
@ -1667,7 +1667,7 @@ static const AVOption libplacebo_options[] = {
|
|||
{"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
|
||||
{"vgamut", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_V_GAMUT}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
|
||||
|
||||
{"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_NB-1, DYNAMIC, .unit = "color_trc"},
|
||||
{"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_EXT_NB-1, DYNAMIC, .unit = "color_trc"},
|
||||
{"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
|
||||
{"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
|
||||
{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
|
||||
|
|
|
|||
|
|
@ -196,6 +196,9 @@ void ff_rtp_send_h264_hevc(AVFormatContext *s1, const uint8_t *buf1, int size)
|
|||
r1 = ff_nal_mp4_find_startcode(r, end, s->nal_length_size);
|
||||
if (!r1)
|
||||
r1 = end;
|
||||
// Check that the last is not truncated
|
||||
if (r1 - r < s->nal_length_size)
|
||||
break;
|
||||
r += s->nal_length_size;
|
||||
} else {
|
||||
while (!*(r++));
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ static void check_idct_dc(HEVCDSPContext *h, int bit_depth)
|
|||
for (i = 2; i <= 5; i++) {
|
||||
int block_size = 1 << i;
|
||||
int size = block_size * block_size;
|
||||
declare_func_emms(AV_CPU_FLAG_MMXEXT, void, int16_t *coeffs);
|
||||
declare_func(void, int16_t *coeffs);
|
||||
|
||||
randomize_buffers(coeffs0, size);
|
||||
memcpy(coeffs1, coeffs0, sizeof(*coeffs0) * size);
|
||||
|
|
|
|||
|
|
@ -267,3 +267,16 @@ FATE_FFMPEG-$(call ENCDEC2, MPEG2VIDEO, FFV1, NUT, HSTACK_FILTER PIPE_PROTOCOL F
|
|||
# test matching by stream disposition
|
||||
fate-ffmpeg-spec-disposition: CMD = framecrc -i $(TARGET_SAMPLES)/mpegts/pmtchange.ts -map '0:disp:visual_impaired+descriptions:1' -c copy
|
||||
FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MPEGTS,,) += fate-ffmpeg-spec-disposition
|
||||
|
||||
# test heif image merging using internally defined filtegraphs
|
||||
# picking the stream group if not mapping any specific stream
|
||||
fate-ffmpeg-heif-merge: CMD = framecrc -i $(TARGET_SAMPLES)/heif-conformance/C007.heic
|
||||
FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, HEVC, HEVC_PARSER) += fate-ffmpeg-heif-merge
|
||||
|
||||
# mapping the stream group
|
||||
fate-ffmpeg-heif-merge-mapped: CMD = framecrc -i $(TARGET_SAMPLES)/heif-conformance/C007.heic -map '[0:g:0]'
|
||||
FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, HEVC, HEVC_PARSER) += fate-ffmpeg-heif-merge-mapped
|
||||
|
||||
# binding the internal filtegraph with a caller defined filtergraph
|
||||
fate-ffmpeg-heif-merge-filtergraph: CMD = framecrc -i $(TARGET_SAMPLES)/heif-conformance/C007.heic -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:g:0]scale=w=1280:h=720[out]" -map "[out]"
|
||||
FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, HEVC, HEVC_PARSER SCALE_FILTER) += fate-ffmpeg-heif-merge-filtergraph
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
#tb 0: 1/1
|
||||
#media_type 0: video
|
||||
#codec_id 0: rawvideo
|
||||
#dimensions 0: 2560x1440
|
||||
#sar 0: 0/1
|
||||
0, 0, 0, 1, 5529600, 0x3bf5d001
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#tb 0: 1/1
|
||||
#media_type 0: video
|
||||
#codec_id 0: rawvideo
|
||||
#dimensions 0: 1280x720
|
||||
#sar 0: 0/1
|
||||
0, 0, 0, 1, 1382400, 0x0f97ebd5
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#tb 0: 1/1
|
||||
#media_type 0: video
|
||||
#codec_id 0: rawvideo
|
||||
#dimensions 0: 2560x1440
|
||||
#sar 0: 0/1
|
||||
0, 0, 0, 1, 5529600, 0x3bf5d001
|
||||
Loading…
Reference in New Issue