Commit aae5ac81 authored by Ronald S. Bultje's avatar Ronald S. Bultje
Browse files

Add interface to output invisible (alt-ref) frames

Addresses part of #310.
parent 4504ae3f
...@@ -65,7 +65,8 @@ typedef struct Dav1dSettings { ...@@ -65,7 +65,8 @@ typedef struct Dav1dSettings {
int operating_point; ///< select an operating point for scalable AV1 bitstreams (0 - 31) int operating_point; ///< select an operating point for scalable AV1 bitstreams (0 - 31)
int all_layers; ///< output all spatial layers of a scalable AV1 biststream int all_layers; ///< output all spatial layers of a scalable AV1 biststream
unsigned frame_size_limit; ///< maximum frame size, in pixels (0 = unlimited) unsigned frame_size_limit; ///< maximum frame size, in pixels (0 = unlimited)
uint8_t reserved[32]; ///< reserved for future use int output_invisible_frames;
uint8_t reserved[28]; ///< reserved for future use
Dav1dPicAllocator allocator; Dav1dPicAllocator allocator;
Dav1dLogger logger; Dav1dLogger logger;
} Dav1dSettings; } Dav1dSettings;
......
...@@ -3196,8 +3196,11 @@ int dav1d_submit_frame(Dav1dContext *const c) { ...@@ -3196,8 +3196,11 @@ int dav1d_submit_frame(Dav1dContext *const c) {
if (out_delayed->p.data[0]) { if (out_delayed->p.data[0]) {
const unsigned progress = atomic_load_explicit(&out_delayed->progress[1], const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed); memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR) if ((out_delayed->visible || c->output_invisible_frames) &&
progress != FRAME_ERROR)
{
dav1d_picture_ref(&c->out, &out_delayed->p); dav1d_picture_ref(&c->out, &out_delayed->p);
}
dav1d_thread_picture_unref(out_delayed); dav1d_thread_picture_unref(out_delayed);
} }
} else { } else {
...@@ -3363,7 +3366,7 @@ int dav1d_submit_frame(Dav1dContext *const c) { ...@@ -3363,7 +3366,7 @@ int dav1d_submit_frame(Dav1dContext *const c) {
// move f->cur into output queue // move f->cur into output queue
if (c->n_fc == 1) { if (c->n_fc == 1) {
if (f->frame_hdr->show_frame) if (f->frame_hdr->show_frame || c->output_invisible_frames)
dav1d_picture_ref(&c->out, &f->sr_cur.p); dav1d_picture_ref(&c->out, &f->sr_cur.p);
} else { } else {
dav1d_thread_picture_ref(out_delayed, &f->sr_cur); dav1d_thread_picture_ref(out_delayed, &f->sr_cur);
......
...@@ -132,6 +132,7 @@ struct Dav1dContext { ...@@ -132,6 +132,7 @@ struct Dav1dContext {
unsigned operating_point_idc; unsigned operating_point_idc;
int all_layers; int all_layers;
unsigned frame_size_limit; unsigned frame_size_limit;
int output_invisible_frames;
int drain; int drain;
Dav1dLogger logger; Dav1dLogger logger;
......
...@@ -75,6 +75,7 @@ COLD void dav1d_default_settings(Dav1dSettings *const s) { ...@@ -75,6 +75,7 @@ COLD void dav1d_default_settings(Dav1dSettings *const s) {
s->operating_point = 0; s->operating_point = 0;
s->all_layers = 1; // just until the tests are adjusted s->all_layers = 1; // just until the tests are adjusted
s->frame_size_limit = 0; s->frame_size_limit = 0;
s->output_invisible_frames = 0;
} }
static void close_internal(Dav1dContext **const c_out, int flush); static void close_internal(Dav1dContext **const c_out, int flush);
...@@ -122,6 +123,7 @@ COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) { ...@@ -122,6 +123,7 @@ COLD int dav1d_open(Dav1dContext **const c_out, const Dav1dSettings *const s) {
c->operating_point = s->operating_point; c->operating_point = s->operating_point;
c->all_layers = s->all_layers; c->all_layers = s->all_layers;
c->frame_size_limit = s->frame_size_limit; c->frame_size_limit = s->frame_size_limit;
c->output_invisible_frames = s->output_invisible_frames;
/* On 32-bit systems extremely large frame sizes can cause overflows in /* On 32-bit systems extremely large frame sizes can cause overflows in
* dav1d_decode_frame() malloc size calculations. Prevent that from occuring * dav1d_decode_frame() malloc size calculations. Prevent that from occuring
...@@ -359,8 +361,11 @@ static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) { ...@@ -359,8 +361,11 @@ static int drain_picture(Dav1dContext *const c, Dav1dPicture *const out) {
const unsigned progress = const unsigned progress =
atomic_load_explicit(&out_delayed->progress[1], atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed); memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR) if ((out_delayed->visible || c->output_invisible_frames) &&
progress != FRAME_ERROR)
{
dav1d_picture_ref(&c->out, &out_delayed->p); dav1d_picture_ref(&c->out, &out_delayed->p);
}
dav1d_thread_picture_unref(out_delayed); dav1d_thread_picture_unref(out_delayed);
if (output_picture_ready(c)) if (output_picture_ready(c))
return output_image(c, out, &c->out); return output_image(c, out, &c->out);
......
...@@ -1517,8 +1517,11 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, int global) { ...@@ -1517,8 +1517,11 @@ int dav1d_parse_obus(Dav1dContext *const c, Dav1dData *const in, int global) {
if (out_delayed->p.data[0]) { if (out_delayed->p.data[0]) {
const unsigned progress = atomic_load_explicit(&out_delayed->progress[1], const unsigned progress = atomic_load_explicit(&out_delayed->progress[1],
memory_order_relaxed); memory_order_relaxed);
if (out_delayed->visible && progress != FRAME_ERROR) if ((out_delayed->visible || c->output_invisible_frames) &&
progress != FRAME_ERROR)
{
dav1d_picture_ref(&c->out, &out_delayed->p); dav1d_picture_ref(&c->out, &out_delayed->p);
}
dav1d_thread_picture_unref(out_delayed); dav1d_thread_picture_unref(out_delayed);
} }
dav1d_thread_picture_ref(out_delayed, dav1d_thread_picture_ref(out_delayed,
......
...@@ -57,29 +57,31 @@ enum { ...@@ -57,29 +57,31 @@ enum {
ARG_ALL_LAYERS, ARG_ALL_LAYERS,
ARG_SIZE_LIMIT, ARG_SIZE_LIMIT,
ARG_CPU_MASK, ARG_CPU_MASK,
ARG_OUTPUT_INVISIBLE,
}; };
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "input", 1, NULL, 'i' }, { "input", 1, NULL, 'i' },
{ "output", 1, NULL, 'o' }, { "output", 1, NULL, 'o' },
{ "quiet", 0, NULL, 'q' }, { "quiet", 0, NULL, 'q' },
{ "demuxer", 1, NULL, ARG_DEMUXER }, { "demuxer", 1, NULL, ARG_DEMUXER },
{ "muxer", 1, NULL, ARG_MUXER }, { "muxer", 1, NULL, ARG_MUXER },
{ "version", 0, NULL, 'v' }, { "version", 0, NULL, 'v' },
{ "frametimes", 1, NULL, ARG_FRAME_TIMES }, { "frametimes", 1, NULL, ARG_FRAME_TIMES },
{ "limit", 1, NULL, 'l' }, { "limit", 1, NULL, 'l' },
{ "skip", 1, NULL, 's' }, { "skip", 1, NULL, 's' },
{ "realtime", 2, NULL, ARG_REALTIME }, { "realtime", 2, NULL, ARG_REALTIME },
{ "realtimecache", 1, NULL, ARG_REALTIME_CACHE }, { "realtimecache", 1, NULL, ARG_REALTIME_CACHE },
{ "framethreads", 1, NULL, ARG_FRAME_THREADS }, { "framethreads", 1, NULL, ARG_FRAME_THREADS },
{ "tilethreads", 1, NULL, ARG_TILE_THREADS }, { "tilethreads", 1, NULL, ARG_TILE_THREADS },
{ "verify", 1, NULL, ARG_VERIFY }, { "verify", 1, NULL, ARG_VERIFY },
{ "filmgrain", 1, NULL, ARG_FILM_GRAIN }, { "filmgrain", 1, NULL, ARG_FILM_GRAIN },
{ "oppoint", 1, NULL, ARG_OPPOINT }, { "oppoint", 1, NULL, ARG_OPPOINT },
{ "alllayers", 1, NULL, ARG_ALL_LAYERS }, { "alllayers", 1, NULL, ARG_ALL_LAYERS },
{ "sizelimit", 1, NULL, ARG_SIZE_LIMIT }, { "sizelimit", 1, NULL, ARG_SIZE_LIMIT },
{ "cpumask", 1, NULL, ARG_CPU_MASK }, { "cpumask", 1, NULL, ARG_CPU_MASK },
{ NULL, 0, NULL, 0 }, { "outputinvisible", 1, NULL, ARG_OUTPUT_INVISIBLE },
{ NULL, 0, NULL, 0 },
}; };
#if ARCH_AARCH64 || ARCH_ARM #if ARCH_AARCH64 || ARCH_ARM
...@@ -120,7 +122,8 @@ static void usage(const char *const app, const char *const reason, ...) { ...@@ -120,7 +122,8 @@ static void usage(const char *const app, const char *const reason, ...) {
" --alllayers $num: output all spatial layers of a scalable AV1 bitstream (default: 1)\n" " --alllayers $num: output all spatial layers of a scalable AV1 bitstream (default: 1)\n"
" --sizelimit $num: stop decoding if the frame size exceeds the specified limit\n" " --sizelimit $num: stop decoding if the frame size exceeds the specified limit\n"
" --verify $md5: verify decoded md5. implies --muxer md5, no output\n" " --verify $md5: verify decoded md5. implies --muxer md5, no output\n"
" --cpumask $mask: restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n"); " --cpumask $mask: restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n"
" --outputinvisible $num: whether to output invisible (alt-ref) frames (default: 0)\n");
exit(1); exit(1);
} }
...@@ -324,6 +327,10 @@ void parse(const int argc, char *const *const argv, ...@@ -324,6 +327,10 @@ void parse(const int argc, char *const *const argv,
dav1d_set_cpu_flags_mask(parse_enum(optarg, cpu_mask_tbl, dav1d_set_cpu_flags_mask(parse_enum(optarg, cpu_mask_tbl,
ARG_CPU_MASK, argv[0])); ARG_CPU_MASK, argv[0]));
break; break;
case ARG_OUTPUT_INVISIBLE:
lib_settings->output_invisible_frames =
!!parse_unsigned(optarg, ARG_OUTPUT_INVISIBLE, argv[0]);
break;
default: default:
usage(argv[0], NULL); usage(argv[0], NULL);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment