Re: [FFmpeg-devel] [PATCH] avformat/segment: add option min_seg_duration

2022-12-27 Thread Gyan Doshi

Plan to push tomorrow.

On 2022-12-25 11:54 pm, Gyan Doshi wrote:



On 2022-12-21 09:08 pm, Gyan Doshi wrote:

New option can be used to avoid creating very short segments with inputs
whose GOP size is variable or unharmonic with segment_time.

Only effective with segment_time.

Comments?


---
  doc/muxers.texi   |  5 +
  libavformat/segment.c | 12 +++-
  2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 4edbb22b00..ed5341be39 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -2369,6 +2369,11 @@ Note that splitting may not be accurate, 
unless you force the

  reference stream key-frames at the given time. See the introductory
  notice and the examples below.
  +@item min_seg_duration @var{time}
+Set minimum segment duration to @var{time}, the value must be a 
duration
+specification. This prevents the muxer ending segments at a duration 
below
+this value. Only effective with @code{segment_time}. Default value 
is "0".

+
  @item segment_atclocktime @var{1|0}
  If set to "1" split at regular clock time intervals starting from 
00:00

  o'clock. The @var{time} value specified in @option{segment_time} is
diff --git a/libavformat/segment.c b/libavformat/segment.c
index c904e20708..c19c2a94ae 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -93,6 +93,7 @@ typedef struct SegmentContext {
  int list_type; ///< set the list type
  AVIOContext *list_pb;  ///< list file put-byte context
  int64_t time;  ///< segment duration
+    int64_t min_seg_duration;  ///< minimum segment duration
  int use_strftime;  ///< flag to expand filename with strftime
  int increment_tc;  ///< flag to increment timecode if found
  @@ -710,6 +711,10 @@ static int seg_init(AVFormatContext *s)
  }
  seg->clocktime_offset = seg->time - 
(seg->clocktime_offset % seg->time);

  }
+    if (seg->min_seg_duration > seg->time) {
+    av_log(s, AV_LOG_ERROR, "min_seg_duration cannot be 
greater than segment_time\n");

+    return AVERROR(EINVAL);
+    }
  }
    if (seg->list) {
@@ -839,7 +844,7 @@ static int seg_write_packet(AVFormatContext *s, 
AVPacket *pkt)

  {
  SegmentContext *seg = s->priv_data;
  AVStream *st = s->streams[pkt->stream_index];
-    int64_t end_pts = INT64_MAX, offset;
+    int64_t end_pts = INT64_MAX, offset, pkt_pts_avtb;
  int start_frame = INT_MAX;
  int ret;
  struct tm ti;
@@ -890,11 +895,15 @@ calc_times:
  pkt->flags & AV_PKT_FLAG_KEY,
  pkt->stream_index == seg->reference_stream_index ? 
seg->frame_count : -1);

  +    if (pkt->pts != AV_NOPTS_VALUE)
+    pkt_pts_avtb = av_rescale_q(pkt->pts, st->time_base, 
AV_TIME_BASE_Q);

+
  if (pkt->stream_index == seg->reference_stream_index &&
  (pkt->flags & AV_PKT_FLAG_KEY || seg->break_non_keyframes) &&
  (seg->segment_frame_count > 0 || seg->write_empty) &&
  (seg->cut_pending || seg->frame_count >= start_frame ||
   (pkt->pts != AV_NOPTS_VALUE &&
+  pkt_pts_avtb - seg->cur_entry.start_pts >= 
seg->min_seg_duration &&

    av_compare_ts(pkt->pts, st->time_base,
  end_pts - seg->time_delta, AV_TIME_BASE_Q) 
>= 0))) {
  /* sanitize end time in case last packet didn't have a 
defined duration */

@@ -1031,6 +1040,7 @@ static const AVOption options[] = {
  { "segment_clocktime_wrap_duration", "set segment clocktime 
wrapping duration", OFFSET(clocktime_wrap_duration), 
AV_OPT_TYPE_DURATION, {.i64 = INT64_MAX}, 0, INT64_MAX, E},
  { "segment_time",  "set segment duration", 
OFFSET(time),AV_OPT_TYPE_DURATION, {.i64 = 200}, INT64_MIN, 
INT64_MAX,   E },
  { "segment_time_delta","set approximation value used for the 
segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 
0, INT64_MAX, E },
+    { "min_seg_duration",  "set minimum segment 
duration",   OFFSET(min_seg_duration), 
AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E },
  { "segment_times", "set segment split time 
points",  OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = 
NULL},  0, 0,   E },
  { "segment_frames",    "set segment split frame 
numbers",    OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = 
NULL},  0, 0,   E },
  { "segment_wrap",  "set number after which the index 
wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 
INT_MAX, E },


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or 

[FFmpeg-devel] 答复: [PATCH] fftools/ffmpeg_ffplay_ffprobe_cmdutils: add -mask_url to replace the protocol address in the command with the asterisk (*)

2022-12-27 Thread Wujian(Chin)
>ffmpeg -h
>segfaults with this patch

My environment test is OK. Details are as follows:
SZV1000266228:/usr1/wujian/build # ffmpeg -h
ffmpeg version N-109445-gcc46f5b Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 7 (GCC)
  configuration: --samples=/usr1/wujian/ffmpeg_master/fate-suite
  libavutil  57. 43.100 / 57. 43.100
  libavcodec 59. 55.103 / 59. 55.103
  libavformat59. 34.102 / 59. 34.102
  libavdevice59.  8.101 / 59.  8.101
  libavfilter 8. 53.100 /  8. 53.100
  libswscale  6.  8.112 /  6.  8.112
  libswresample   4.  9.100 /  4.  9.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] 
outfile}...

Getting help:
-h  -- print basic options
-h long -- print more options
-h full -- print all options (including all format and codec specific 
options, very long)
-h type=name -- print all options for the named 
decoder/encoder/demuxer/muxer/filter/bsf/protocol
See man ffmpeg for detailed description of the options.

Print help / information / capabilities:
-L  show license
-h topicshow help
-? topicshow help
-help topic show help
--help topicshow help
-versionshow version
-buildconf  show build configuration
-formatsshow available formats
-muxers show available muxers
-demuxers   show available demuxers
-devicesshow available devices
-codecs show available codecs
-decoders   show available decoders
-encoders   show available encoders
-bsfs   show available bit stream filters
-protocols  show available protocols
-filtersshow available filters
-pix_fmts   show available pixel formats
-layoutsshow standard channel layouts
-sample_fmtsshow available audio sample formats
-dispositions   show available stream dispositions
-colors show available color names
-sources device list sources of the input device
-sinks device   list sinks of the output device
-hwaccels   show available HW acceleration methods

Global options (affect whole program instead of just one file):
-loglevel loglevel  set logging level
-v loglevel set logging level
-report generate a report
-max_alloc bytesset maximum size of a single allocated block
-y  overwrite output files
-n  never overwrite output files
-ignore_unknown Ignore unknown stream types
-filter_threads number of non-complex filter threads
-filter_complex_threads  number of threads for -filter_complex
-stats  print progress report during encoding
-max_error_rate maximum error rate  ratio of decoding errors (0.0: no errors, 
1.0: 100% errors) above which ffmpeg returns an error instead of success.

Per-file main options:
-f fmt  force format
-c codeccodec name
-codec codeccodec name
-pre preset preset name
-map_metadata outfile[,metadata]:infile[,metadata]  set metadata information of 
outfile from infile
-t duration record or transcode "duration" seconds of audio/video
-to time_stop   record or transcode stop time
-fs limit_size  set the limit file size in bytes
-ss time_offset the start time offset
-sseof time_off set the start time offset relative to EOF
-seek_timestamp enable/disable seeking by timestamp with -ss
-timestamp time set the recording timestamp ('now' to set the current time)
-metadata string=string  add metadata
-program title=string:st=number...  add program with specified streams
-target typespecify target file type ("vcd", "svcd", "dvd", "dv" or 
"dv50" with optional prefixes "pal-", "ntsc-" or "film-")
-apad   audio pad
-frames number  set the number of frames to output
-filter filter_graph  set stream filtergraph
-filter_script filename  read stream filtergraph description from a file
-reinit_filter  reinit filtergraph on input parameter changes
-discarddiscard
-dispositiondisposition

Video options:
-vframes number set the number of video frames to output
-r rate set frame rate (Hz value, fraction or abbreviation)
-fpsmax rateset max frame rate (Hz value, fraction or abbreviation)
-s size set frame size (WxH or abbreviation)
-aspect aspect  set aspect ratio (4:3, 16:9 or 1., 1.)
-display_rotation angle  set pure counter-clockwise rotation in degrees for 
stream(s)
-display_hflip  set display horizontal flip for stream(s) (overrides any 
display rotation if it is not set)
-display_vflip  set display vertical flip for stream(s) (overrides any 
display rotation if it is not set)
-vn disable video
-vcodec codec   force video codec ('copy' to copy stream)
-timecode hh:mm:ss[:;.]ff  set initial TimeCode value.
-pass n 

[FFmpeg-devel] [PATCH 3/3] avformat/mxfdec: check number of index table entires more strictly

2022-12-27 Thread Marton Balint
Let's ignore the index table if the number of index entries does not match the
index duration (or the special AVID index entry counts).

Fixes: OOM
Fixes: 
50551/clusterfuzz-testcase-minimized-ffmpeg_dem_MXF_fuzzer-6607795234930688

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Marton Balint 
---
 libavformat/mxfdec.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 2e61e77d67..0dc61648b1 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -1937,6 +1937,14 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, 
MXFIndexTable *index_ta
 return 0;
 }
 
+if (s->nb_index_entries != s->index_duration &&
+s->nb_index_entries != s->index_duration + 1 &&
+s->nb_index_entries != s->index_duration * 2 + 1) {
+index_table->nb_ptses = 0;
+av_log(mxf->fc, AV_LOG_ERROR, "ignoring IndexSID %d, duration does 
not match nb_index_entries\n", s->index_sid);
+return 0;
+}
+
 index_table->nb_ptses += s->index_duration;
 }
 
-- 
2.35.3

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH 2/3] avformat/mxfdec: support Avid files with an extra index entry

2022-12-27 Thread Marton Balint
Signed-off-by: Marton Balint 
---
 libavformat/mxfdec.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index ad4ee15570..2e61e77d67 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -1991,11 +1991,11 @@ static int mxf_compute_ptses_fake_index(MXFContext 
*mxf, MXFIndexTable *index_ta
 int index_delta = 1;
 int n = s->nb_index_entries;
 
-if (s->nb_index_entries == 2 * s->index_duration + 1) {
+if (s->nb_index_entries == 2 * s->index_duration + 1)
 index_delta = 2;/* Avid index */
-/* ignore the last entry - it's the size of the essence container 
*/
+if (s->nb_index_entries == index_delta * s->index_duration + 1)
+/* ignore the last entry - it's the size of the essence container 
in Avid */
 n--;
-}
 
 for (j = 0; j < n; j += index_delta, x++) {
 int offset = s->temporal_offset_entries[j] / index_delta;
-- 
2.35.3

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH 1/3] avformat/mxfdec: check index entry array size

2022-12-27 Thread Marton Balint
Signed-off-by: Marton Balint 
---
 libavformat/mxfdec.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index e6118e141d..ad4ee15570 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -1198,11 +1198,15 @@ static int mxf_read_essence_container_data(void *arg, 
AVIOContext *pb, int tag,
 static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment 
*segment)
 {
 int i, length;
+uint32_t nb_index_entries;
 
 if (segment->temporal_offset_entries)
 return AVERROR_INVALIDDATA;
 
-segment->nb_index_entries = avio_rb32(pb);
+nb_index_entries = avio_rb32(pb);
+if (nb_index_entries > INT_MAX)
+return AVERROR_INVALIDDATA;
+segment->nb_index_entries = nb_index_entries;
 
 length = avio_rb32(pb);
 if(segment->nb_index_entries && length < 11)
-- 
2.35.3

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avformat/mxfdec: Check index_duration

2022-12-27 Thread Marton Balint



On Tue, 27 Dec 2022, Marton Balint wrote:




On Tue, 27 Dec 2022, Michael Niedermayer wrote:


 On Tue, Dec 27, 2022 at 07:05:44PM +0100, Marton Balint wrote:



 On Mon, 26 Dec 2022, Michael Niedermayer wrote:


 On Mon, Dec 26, 2022 at 11:32:48AM +0100, Tomas Härdin wrote:

 lör 2022-12-24 klockan 23:50 +0100 skrev Michael Niedermayer:


  index_table->nb_ptses += s->index_duration;
 +    // If index_duration is substantially larger than
 nb_index_entries then this algorithm which
 +    // allocates index_duration elements is a bad idea. All
 files i tried have it equal
 +    if (s->index_duration > 10LL * s->nb_index_entries)
 +    return AVERROR_PATCHWELCOME;


 I was going to say this can overflow but the 10LL ensures it can't. So
 looks OK.


 will apply


 Please don't, as far as I see this disallows the usage of partial index
 tables, so practically rejecting valid files, which is not OK.


 can you share a file that would break ?


I don't have such file. But the MXF specs (SMPTE 377-1-2009) explictly 
defines the concept of partial index tables:


"Where all Index Table segments are contiguous, or there is only one segment, 
but not all Edit Units in the Essence Container are indexed, these tables are 
called Partial Index Tables."


As far as I see here nb_index_entries is corresponding to the number of 
indexed edit units, and the number is allowed to be smaller than the index 
duration, because not all edit units have to be indexed.


I read the specs again, and it seems that I misread it the first time, 
because partial index tables mean that the index segments have no gaps 
between them, but the index still not cover the whole essence. So it is 
not referring to the index entries in the segment.


So, in principal your patch *might* be OK. However, existing code simply 
ignores a corrupt index table, does not reject it. I kind of prefer we 
make the check more strict, but gracefully allow corrupted index by 
ignoring it fully.


I will post a follow up patch series.

Regards,
Marton
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] Rework color quantization in palette{gen,use}

2022-12-27 Thread Clément Bœsch
On Tue, Nov 08, 2022 at 10:37:59PM +, Soft Works wrote:
[...]
> For completeness, I'm also including the recent comparison, but it 
> seems you're already on track in this regard.

If you remove the alpha from the input image you'll see that it performs
pretty much as good. You can check with the last results.

Please note though that it's expected to have elbg or even pngquant to get
better results, because they're relying on clustering algorithms afaik,
which are slower (but more efficient). It's a trade-off.

[...]
> Then I'd have a question about your file07 example. Is this the 
> original file or did I mix something up?
> 
> http://big.pkh.me/pal/output/0-current/file07/cfg00/0-ref.png
> 
> I'm wondering because the image is full or weird artifacts at the 
> edges of the green (and other) leafes.
> 

I'm assuming this was the image with 1M+ colors; sorry I removed the file,
but yeah given the URL it was the reference file with weird artifacts
(it's a synthetic sample after all).

[...]
> PS: I'd be curious what you think about the elbg image...

If you want to look at elbg vs palette filters, make sure you disable
dithering (elbg doesn't have any), and make sure to use the sample without
transparency. You'll see that they perform mostly the same.

-- 
Clément B.
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH 12/15] avfilter/palettegen: base split decision on a perceptual model

2022-12-27 Thread Clément Bœsch
On Sat, Nov 05, 2022 at 08:07:42PM +0100, Andreas Rheinhardt wrote:
[...]
> You are adding floating point to places where there was no floating
> point before (some other patches of this patchset do the same). Is this
> still bitexact across all supported arches?

It should be good with the last iteration I just submitted.

Regards,

-- 
Clément B.
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 08/32] avfilter/paletteuse: remove redundant alpha condition

2022-12-27 Thread Clément Bœsch
This is redundant with a != 0xff below.
---
 libavfilter/vf_paletteuse.c | 7 +--
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 8954a02524..0861a70a0b 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -599,7 +599,6 @@ DECLARE_CMP_FUNC(b, 2)
 static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
 
 static int get_next_color(const uint8_t *color_used, const uint32_t *palette,
-  const int trans_thresh,
   int *component, const struct color_rect *box)
 {
 int wr, wg, wb;
@@ -619,10 +618,6 @@ static int get_next_color(const uint8_t *color_used, const 
uint32_t *palette,
 const uint8_t g = c >>  8 & 0xff;
 const uint8_t b = c   & 0xff;
 
-if (a < trans_thresh) {
-continue;
-}
-
 if (color_used[i] || (a != 0xff) ||
 r < box->min[0] || g < box->min[1] || b < box->min[2] ||
 r > box->max[0] || g > box->max[1] || b > box->max[2])
@@ -674,7 +669,7 @@ static int colormap_insert(struct color_node *map,
 int node_left_id = -1, node_right_id = -1;
 struct color_node *node;
 struct color_rect box1, box2;
-const int pal_id = get_next_color(color_used, palette, trans_thresh, 
, box);
+const int pal_id = get_next_color(color_used, palette, , box);
 
 if (pal_id < 0)
 return -1;
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 32/32] avfilter/palette{gen, use}: misc for-loop cosmetics

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 19 +--
 libavfilter/vf_paletteuse.c | 22 +-
 2 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 97e12f7274..4b69d3c63b 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -209,13 +209,13 @@ static void compute_box_stats(PaletteGenContext *s, 
struct range_box *box)
  */
 static int get_next_box_id_to_split(PaletteGenContext *s)
 {
-int box_id, best_box_id = -1;
+int best_box_id = -1;
 int64_t max_score = -1;
 
 if (s->nb_boxes == s->max_colors - s->reserve_transparent)
 return -1;
 
-for (box_id = 0; box_id < s->nb_boxes; box_id++) {
+for (int box_id = 0; box_id < s->nb_boxes; box_id++) {
 const struct range_box *box = >boxes[box_id];
 if (s->boxes[box_id].len >= 2 && box->cut_score > max_score) {
 best_box_id = box_id;
@@ -250,13 +250,13 @@ static void split_box(PaletteGenContext *s, struct 
range_box *box, int n)
 static void write_palette(AVFilterContext *ctx, AVFrame *out)
 {
 const PaletteGenContext *s = ctx->priv;
-int x, y, box_id = 0;
+int box_id = 0;
 uint32_t *pal = (uint32_t *)out->data[0];
 const int pal_linesize = out->linesize[0] >> 2;
 uint32_t last_color = 0;
 
-for (y = 0; y < out->height; y++) {
-for (x = 0; x < out->width; x++) {
+for (int y = 0; y < out->height; y++) {
+for (int x = 0; x < out->width; x++) {
 if (box_id < s->nb_boxes) {
 pal[x] = s->boxes[box_id++].color;
 if ((x || y) && pal[x] == last_color)
@@ -282,16 +282,16 @@ static void write_palette(AVFilterContext *ctx, AVFrame 
*out)
  */
 static struct color_ref **load_color_refs(const struct hist_node *hist, int 
nb_refs)
 {
-int i, j, k = 0;
+int k = 0;
 struct color_ref **refs = av_malloc_array(nb_refs, sizeof(*refs));
 
 if (!refs)
 return NULL;
 
-for (j = 0; j < HIST_SIZE; j++) {
+for (int j = 0; j < HIST_SIZE; j++) {
 const struct hist_node *node = [j];
 
-for (i = 0; i < node->nb_entries; i++)
+for (int i = 0; i < node->nb_entries; i++)
 refs[k++] = >entries[i];
 }
 
@@ -391,12 +391,11 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
  */
 static int color_inc(struct hist_node *hist, uint32_t color)
 {
-int i;
 const uint32_t hash = ff_lowbias32(color) & (HIST_SIZE - 1);
 struct hist_node *node = [hash];
 struct color_ref *e;
 
-for (i = 0; i < node->nb_entries; i++) {
+for (int i = 0; i < node->nb_entries; i++) {
 e = >entries[i];
 if (e->color == color) {
 e->count++;
diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index e3462b4abb..33d0b0e722 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -231,7 +231,6 @@ struct stack_node {
  */
 static av_always_inline int color_get(PaletteUseContext *s, uint32_t color)
 {
-int i;
 struct color_info clrinfo;
 const uint32_t hash = ff_lowbias32(color) & (CACHE_SIZE - 1);
 struct cache_node *node = >cache[hash];
@@ -242,7 +241,7 @@ static av_always_inline int color_get(PaletteUseContext *s, 
uint32_t color)
 return s->transparency_index;
 }
 
-for (i = 0; i < node->nb_entries; i++) {
+for (int i = 0; i < node->nb_entries; i++) {
 e = >entries[i];
 if (e->color == color)
 return e->pal_entry;
@@ -284,7 +283,6 @@ static av_always_inline int set_frame(PaletteUseContext *s, 
AVFrame *out, AVFram
   int x_start, int y_start, int w, int h,
   enum dithering_mode dither)
 {
-int x, y;
 const int src_linesize = in ->linesize[0] >> 2;
 const int dst_linesize = out->linesize[0];
 uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize;
@@ -293,8 +291,8 @@ static av_always_inline int set_frame(PaletteUseContext *s, 
AVFrame *out, AVFram
 w += x_start;
 h += y_start;
 
-for (y = y_start; y < h; y++) {
-for (x = x_start; x < w; x++) {
+for (int y = y_start; y < h; y++) {
+for (int x = x_start; x < w; x++) {
 int er, eg, eb;
 
 if (dither == DITHERING_BAYER) {
@@ -467,7 +465,7 @@ static int get_next_color(const uint8_t *color_used, const 
uint32_t *palette,
   int *component, const struct color_rect *box)
 {
 int wL, wa, wb;
-int i, longest = 0;
+int longest = 0;
 unsigned nb_color = 0;
 struct color_rect ranges;
 struct color tmp_pal[256];
@@ -476,7 +474,7 @@ static int get_next_color(const uint8_t *color_used, const 
uint32_t *palette,
 ranges.min[0] = ranges.min[1] = ranges.min[2] = 0x;
 ranges.max[0] = ranges.max[1] = ranges.max[2] = -0x;
 
-for (i = 0; i < AVPALETTE_COUNT; i++) {
+for (int i = 0; i < 

[FFmpeg-devel] [PATCH v2 31/32] avfilter/paletteuse: move r, g, b computation in a more local scope

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_paletteuse.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 33b8e70293..e3462b4abb 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -262,9 +262,6 @@ static av_always_inline int color_get(PaletteUseContext *s, 
uint32_t color)
 static av_always_inline int get_dst_color_err(PaletteUseContext *s,
   uint32_t c, int *er, int *eg, 
int *eb)
 {
-const uint8_t r = c >> 16 & 0xff;
-const uint8_t g = c >>  8 & 0xff;
-const uint8_t b = c   & 0xff;
 uint32_t dstc;
 const int dstx = color_get(s, c);
 if (dstx < 0)
@@ -273,6 +270,9 @@ static av_always_inline int 
get_dst_color_err(PaletteUseContext *s,
 if (dstx == s->transparency_index) {
 *er = *eg = *eb = 0;
 } else {
+const uint8_t r = c >> 16 & 0xff;
+const uint8_t g = c >>  8 & 0xff;
+const uint8_t b = c   & 0xff;
 *er = (int)r - (int)(dstc >> 16 & 0xff);
 *eg = (int)g - (int)(dstc >>  8 & 0xff);
 *eb = (int)b - (int)(dstc   & 0xff);
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 07/32] avfilter/paletteuse: remove unused alpha split dimension

2022-12-27 Thread Clément Bœsch
The equalities in the w{r,g,b} range checks make sure longest is never
0. Even if the alpha ended up being selected in get_next_color() it
would cause underread memory accesses in its caller (colormap_insert).
---
 libavfilter/vf_paletteuse.c | 33 -
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index f43f077454..8954a02524 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -211,7 +211,7 @@ static void colormap_nearest_node(const struct color_node 
*map,
   struct nearest_color *nearest)
 {
 const struct color_node *kd = map + node_pos;
-const int shift = (3 - kd->split) * 8;
+const int shift = (2 - kd->split) * 8;
 int dx, nearer_kd_id, further_kd_id;
 const uint32_t current = kd->val;
 const int current_to_target = diff(target, current, trans_thresh);
@@ -270,7 +270,7 @@ static av_always_inline uint8_t 
colormap_nearest_iterative(const struct color_no
 
 /* Check if it's not a leaf */
 if (kd->left_id != -1 || kd->right_id != -1) {
-const int shift = (3 - kd->split) * 8;
+const int shift = (2 - kd->split) * 8;
 const int dx = (target>>shift & 0xff) - (current>>shift & 0xff);
 int nearer_kd_id, further_kd_id;
 
@@ -497,7 +497,7 @@ static void disp_node(AVBPrint *buf,
 const uint32_t fontcolor = (node->val>>16 & 0xff) > 0x50 &&
(node->val>> 8 & 0xff) > 0x50 &&
(node->val & 0xff) > 0x50 ? 0 : 0xff;
-const int rgb_comp = node->split - 1;
+const int rgb_comp = node->split;
 av_bprintf(buf, "%*cnode%d ["
"label=\"%c%02X%c%02X%c%02X%c\" "
"fillcolor=\"#%06"PRIX32"\" "
@@ -588,16 +588,15 @@ static int cmp_##name(const void *pa, const void *pb)   \
 {   \
 const struct color *a = pa; \
 const struct color *b = pb; \
-return   (int)(a->value >> (8 * (3 - (pos))) & 0xff) \
-   - (int)(b->value >> (8 * (3 - (pos))) & 0xff);\
+return   (int)(a->value >> (8 * (2 - (pos))) & 0xff) \
+   - (int)(b->value >> (8 * (2 - (pos))) & 0xff);\
 }
 
-DECLARE_CMP_FUNC(a, 0)
-DECLARE_CMP_FUNC(r, 1)
-DECLARE_CMP_FUNC(g, 2)
-DECLARE_CMP_FUNC(b, 3)
+DECLARE_CMP_FUNC(r, 0)
+DECLARE_CMP_FUNC(g, 1)
+DECLARE_CMP_FUNC(b, 2)
 
-static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b};
+static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
 
 static int get_next_color(const uint8_t *color_used, const uint32_t *palette,
   const int trans_thresh,
@@ -650,9 +649,9 @@ static int get_next_color(const uint8_t *color_used, const 
uint32_t *palette,
 wr = ranges.max[0] - ranges.min[0];
 wg = ranges.max[1] - ranges.min[1];
 wb = ranges.max[2] - ranges.min[2];
-if (wr >= wg && wr >= wb) longest = 1;
-if (wg >= wr && wg >= wb) longest = 2;
-if (wb >= wr && wb >= wg) longest = 3;
+if (wr >= wg && wr >= wb) longest = 0;
+if (wg >= wr && wg >= wb) longest = 1;
+if (wb >= wr && wb >= wg) longest = 2;
 cmpf = cmp_funcs[longest];
 *component = longest;
 
@@ -692,13 +691,13 @@ static int colormap_insert(struct color_node *map,
 
 /* get the two boxes this node creates */
 box1 = box2 = *box;
-comp_value = node->val >> ((3 - component) * 8) & 0xff;
-box1.max[component-1] = comp_value;
-box2.min[component-1] = FFMIN(comp_value + 1, 255);
+comp_value = node->val >> ((2 - component) * 8) & 0xff;
+box1.max[component] = comp_value;
+box2.min[component] = FFMIN(comp_value + 1, 255);
 
 node_left_id = colormap_insert(map, color_used, nb_used, palette, 
trans_thresh, );
 
-if (box2.min[component-1] <= box2.max[component-1])
+if (box2.min[component] <= box2.max[component])
 node_right_id = colormap_insert(map, color_used, nb_used, palette, 
trans_thresh, );
 
 node->left_id  = node_left_id;
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 30/32] avfilter/paletteuse: remove mean error tool

2022-12-27 Thread Clément Bœsch
This belongs in another filter.
---
 libavfilter/vf_paletteuse.c | 31 ---
 1 file changed, 31 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 690422a842..33b8e70293 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -121,7 +121,6 @@ static const AVOption paletteuse_options[] = {
 
 /* following are the debug options, not part of the official API */
 { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", 
OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
-{ "mean_err", "compute and print mean error", OFFSET(calc_mean_err), 
AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
 { NULL }
 };
 
@@ -606,34 +605,6 @@ static void load_colormap(PaletteUseContext *s)
 disp_tree(s->map, s->dot_filename);
 }
 
-static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
- const AVFrame *in2, int frame_count)
-{
-int x, y;
-const uint32_t *palette = s->palette;
-uint32_t *src1 = (uint32_t *)in1->data[0];
-uint8_t  *src2 = in2->data[0];
-const int src1_linesize = in1->linesize[0] >> 2;
-const int src2_linesize = in2->linesize[0];
-const float div = in1->width * in1->height * 3;
-unsigned mean_err = 0;
-
-for (y = 0; y < in1->height; y++) {
-for (x = 0; x < in1->width; x++) {
-const struct color_info c1 = get_color_from_srgb(0xff00 | 
src1[x]);
-const struct color_info c2 = get_color_from_srgb(0xff00 | 
palette[src2[x]]);
-mean_err += diff(, , s->trans_thresh);
-}
-src1 += src1_linesize;
-src2 += src2_linesize;
-}
-
-s->total_mean_err += mean_err;
-
-av_log(NULL, AV_LOG_INFO, "MEP:%.3f TotalMEP:%.3f\n",
-   mean_err / div, s->total_mean_err / (div * frame_count));
-}
-
 static void set_processing_window(enum diff_mode diff_mode,
   const AVFrame *prv_src, const AVFrame 
*cur_src,
   const AVFrame *prv_dst,   AVFrame 
*cur_dst,
@@ -759,8 +730,6 @@ static int apply_palette(AVFilterLink *inlink, AVFrame *in, 
AVFrame **outf)
 return ret;
 }
 memcpy(out->data[1], s->palette, AVPALETTE_SIZE);
-if (s->calc_mean_err)
-debug_mean_error(s, in, out, inlink->frame_count_out);
 *outf = out;
 return 0;
 }
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 06/32] avfilter/paletteuse: name target color arg consistently in colormap functions

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_paletteuse.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index fb4016b11c..f43f077454 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -180,7 +180,7 @@ static av_always_inline int diff(const uint32_t a, const 
uint32_t b, const int t
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const uint32_t argb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const uint32_t target, const int trans_thresh)
 {
 int i, pal_id = -1, min_dist = INT_MAX;
 
@@ -188,7 +188,7 @@ static av_always_inline uint8_t 
colormap_nearest_bruteforce(const uint32_t *pale
 const uint32_t c = palette[i];
 
 if (c >> 24 >= trans_thresh) { // ignore transparent entry
-const int d = diff(palette[i], argb, trans_thresh);
+const int d = diff(palette[i], target, trans_thresh);
 if (d < min_dist) {
 pal_id = i;
 min_dist = d;
@@ -235,10 +235,10 @@ static void colormap_nearest_node(const struct color_node 
*map,
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_recursive(const struct 
color_node *node, const uint8_t rgb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_recursive(const struct 
color_node *node, const uint8_t target, const int trans_thresh)
 {
 struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
-colormap_nearest_node(node, 0, rgb, trans_thresh, );
+colormap_nearest_node(node, 0, target, trans_thresh, );
 return node[res.node_pos].palette_id;
 }
 
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 29/32] avfilter/paletteuse: remove alternative search methods

2022-12-27 Thread Clément Bœsch
This is a maintenance pain more than anything. It appears to make the
code slightly faster as a side effect.
---
 libavfilter/vf_paletteuse.c | 220 +---
 1 file changed, 31 insertions(+), 189 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 0342002b15..690422a842 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -45,13 +45,6 @@ enum dithering_mode {
 NB_DITHERING
 };
 
-enum color_search_method {
-COLOR_SEARCH_NNS_ITERATIVE,
-COLOR_SEARCH_NNS_RECURSIVE,
-COLOR_SEARCH_BRUTEFORCE,
-NB_COLOR_SEARCHES
-};
-
 enum diff_mode {
 DIFF_MODE_NONE,
 DIFF_MODE_RECTANGLE,
@@ -107,10 +100,8 @@ typedef struct PaletteUseContext {
 
 /* debug options */
 char *dot_filename;
-int color_search_method;
 int calc_mean_err;
 uint64_t total_mean_err;
-int debug_accuracy;
 } PaletteUseContext;
 
 #define OFFSET(x) offsetof(PaletteUseContext, x)
@@ -130,12 +121,7 @@ static const AVOption paletteuse_options[] = {
 
 /* following are the debug options, not part of the official API */
 { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", 
OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
-{ "color_search", "set reverse colormap color search method", 
OFFSET(color_search_method), AV_OPT_TYPE_INT, 
{.i64=COLOR_SEARCH_NNS_RECURSIVE}, 0, NB_COLOR_SEARCHES-1, FLAGS, "search" },
-{ "nns_iterative", "iterative search", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, INT_MIN, INT_MAX, FLAGS, 
"search" },
-{ "nns_recursive", "recursive search", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_RECURSIVE}, INT_MIN, INT_MAX, FLAGS, 
"search" },
-{ "bruteforce","brute-force into the palette", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE},INT_MIN, INT_MAX, FLAGS, 
"search" },
 { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), 
AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
-{ "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), 
AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
 { NULL }
 };
 
@@ -193,26 +179,6 @@ static struct color_info get_color_from_srgb(uint32_t srgb)
 return ret;
 }
 
-static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const struct color_info *target, const int trans_thresh)
-{
-int i, pal_id = -1, min_dist = INT_MAX;
-
-for (i = 0; i < AVPALETTE_COUNT; i++) {
-const uint32_t c = palette[i];
-
-if (c >> 24 >= trans_thresh) { // ignore transparent entry
-const struct color_info pal_color = 
get_color_from_srgb(palette[i]);
-const int d = diff(_color, target, trans_thresh);
-if (d < min_dist) {
-pal_id = i;
-min_dist = d;
-}
-}
-}
-return pal_id;
-}
-
-/* Recursive form, simpler but a bit slower. Kept for reference. */
 struct nearest_color {
 int node_pos;
 int dist_sqd;
@@ -248,7 +214,7 @@ static void colormap_nearest_node(const struct color_node 
*map,
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_recursive(const struct 
color_node *node, const struct color_info *target, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest(const struct color_node 
*node, const struct color_info *target, const int trans_thresh)
 {
 struct nearest_color res = {.dist_sqd = INT32_MAX, .node_pos = -1};
 colormap_nearest_node(node, 0, target, trans_thresh, );
@@ -260,88 +226,11 @@ struct stack_node {
 int dx2;
 };
 
-static av_always_inline uint8_t colormap_nearest_iterative(const struct 
color_node *root, const struct color_info *target, const int trans_thresh)
-{
-int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
-struct stack_node nodes[16];
-struct stack_node *node = [0];
-
-for (;;) {
-
-const struct color_node *kd = [cur_color_id];
-const struct color_info *current = >c;
-const int current_to_target = diff(target, current, trans_thresh);
-
-/* Compare current color node to the target and update our best node if
- * it's actually better. */
-if (current_to_target < best_dist) {
-best_node_id = cur_color_id;
-if (!current_to_target)
-goto end; // exact match, we can return immediately
-best_dist = current_to_target;
-}
-
-/* Check if it's not a leaf */
-if (kd->left_id != -1 || kd->right_id != -1) {
-const int dx = target->lab[kd->split] - current->lab[kd->split];
-int nearer_kd_id, further_kd_id;
-
-/* Define which side is the most interesting. */
-if (dx <= 0) nearer_kd_id = kd->left_id,  further_kd_id = 
kd->right_id;
-else nearer_kd_id = kd->right_id, further_kd_id = 
kd->left_id;
-
-

[FFmpeg-devel] [PATCH v2 28/32] avfilter/paletteuse: switch to recursive method

2022-12-27 Thread Clément Bœsch
It appears faster than the iterative method on my machine (1.06x
faster), so I'm guessing compilers improved over time (the iterative
version was slightly faster in the past).
---
 libavfilter/vf_paletteuse.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index c2d6333662..0342002b15 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -130,7 +130,7 @@ static const AVOption paletteuse_options[] = {
 
 /* following are the debug options, not part of the official API */
 { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", 
OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
-{ "color_search", "set reverse colormap color search method", 
OFFSET(color_search_method), AV_OPT_TYPE_INT, 
{.i64=COLOR_SEARCH_NNS_ITERATIVE}, 0, NB_COLOR_SEARCHES-1, FLAGS, "search" },
+{ "color_search", "set reverse colormap color search method", 
OFFSET(color_search_method), AV_OPT_TYPE_INT, 
{.i64=COLOR_SEARCH_NNS_RECURSIVE}, 0, NB_COLOR_SEARCHES-1, FLAGS, "search" },
 { "nns_iterative", "iterative search", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, INT_MIN, INT_MAX, FLAGS, 
"search" },
 { "nns_recursive", "recursive search", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_RECURSIVE}, INT_MIN, INT_MAX, FLAGS, 
"search" },
 { "bruteforce","brute-force into the palette", 0, 
AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE},INT_MIN, INT_MAX, FLAGS, 
"search" },
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 27/32] avfilter/paletteuse: use lowbias32 for color hashing

2022-12-27 Thread Clément Bœsch
Impact is more negligible than previous commit but still faster (1.02x).
---
 libavfilter/vf_paletteuse.c | 8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index c32b73ab9a..c2d6333662 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -70,8 +70,7 @@ struct color_node {
 int left_id, right_id;
 };
 
-#define NBITS 5
-#define CACHE_SIZE (1<<(3*NBITS))
+#define CACHE_SIZE (1<<15)
 
 struct cached_color {
 uint32_t color;
@@ -346,10 +345,7 @@ static av_always_inline int color_get(PaletteUseContext 
*s, uint32_t color,
 {
 int i;
 struct color_info clrinfo;
-const uint8_t rhash = (color>>16) & ((1<> 8) & ((1

[FFmpeg-devel] [PATCH v2 26/32] avfilter/palettegen: use lowbias32 for color hashing

2022-12-27 Thread Clément Bœsch
1.12x faster overall in palettegen on my machine.
---
 libavfilter/vf_palettegen.c | 19 ++-
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 6301cf6358..97e12f7274 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -63,8 +63,7 @@ enum {
 NB_STATS_MODE
 };
 
-#define NBITS 5
-#define HIST_SIZE (1<<(3*NBITS))
+#define HIST_SIZE (1<<15)
 
 typedef struct PaletteGenContext {
 const AVClass *class;
@@ -387,27 +386,13 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 return out;
 }
 
-/**
- * Hashing function for the color.
- * It keeps the NBITS least significant bit of each component to make it
- * "random" even if the scene doesn't have much different colors.
- */
-static inline unsigned color_hash(uint32_t color)
-{
-const uint8_t r = color >> 16 & ((1<>  8 & ((1

[FFmpeg-devel] [PATCH v2 25/32] avfilter/palette: add lowbias32 hashing

2022-12-27 Thread Clément Bœsch
---
 libavfilter/palette.c | 10 ++
 libavfilter/palette.h |  5 +
 2 files changed, 15 insertions(+)

diff --git a/libavfilter/palette.c b/libavfilter/palette.c
index 03e48fc71e..e21ab6ff4d 100644
--- a/libavfilter/palette.c
+++ b/libavfilter/palette.c
@@ -208,3 +208,13 @@ uint32_t ff_oklab_int_to_srgb_u8(struct Lab c)
 
 return r<<16 | g<<8 | b;
 }
+
+uint32_t ff_lowbias32(uint32_t x)
+{
+x ^= x >> 16;
+x *= 0x7feb352d;
+x ^= x >> 15;
+x *= 0x846ca68b;
+x ^= x >> 16;
+return x;
+}
diff --git a/libavfilter/palette.h b/libavfilter/palette.h
index 6839bf6fc6..d3acc854ba 100644
--- a/libavfilter/palette.h
+++ b/libavfilter/palette.h
@@ -55,4 +55,9 @@ struct Lab ff_srgb_u8_to_oklab_int(uint32_t srgb);
  */
 uint32_t ff_oklab_int_to_srgb_u8(struct Lab c);
 
+/*
+ * lowbias32 hashing from https://nullprogram.com/blog/2018/07/31/
+ */
+uint32_t ff_lowbias32(uint32_t x);
+
 #endif /* AVFILTER_PALETTE_H */
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 24/32] avfilter/palette{gen, use}: update Copyright after recent changes

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 1 +
 libavfilter/vf_paletteuse.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 507690fa82..6301cf6358 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Stupeflix
+ * Copyright (c) 2022 Clément Bœsch 
  *
  * This file is part of FFmpeg.
  *
diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 3af121b1eb..c32b73ab9a 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2015 Stupeflix
+ * Copyright (c) 2022 Clément Bœsch 
  *
  * This file is part of FFmpeg.
  *
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 23/32] avfilter/palettegen: use libc qsort

2022-12-27 Thread Clément Bœsch
Now that the sort function is deterministic, we can rely on the libc
sorting function.
---
 libavfilter/vf_palettegen.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 784e81b875..507690fa82 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -26,7 +26,6 @@
 #include "libavutil/avassert.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
-#include "libavutil/qsort.h"
 #include "libavutil/intreadwrite.h"
 #include "avfilter.h"
 #include "internal.h"
@@ -352,7 +351,7 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 /* sort the range by its major axis if it's not already sorted */
 if (box->sorted_by != box->major_axis) {
 cmp_func cmpf = cmp_funcs[box->major_axis];
-AV_QSORT(>refs[box->start], box->len, const struct color_ref *, 
cmpf);
+qsort(>refs[box->start], box->len, sizeof(struct color_ref *), 
cmpf);
 box->sorted_by = box->major_axis;
 }
 
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 22/32] avfilter/palettegen: make refs order deterministic

2022-12-27 Thread Clément Bœsch
Currently, in case of equality on the first color channel, the order of
the ref colors is defined by the hashing function. This commit makes the
sorting deterministic and improve the hierarchical ordering.
---
 libavfilter/vf_palettegen.c| 61 ++
 tests/ref/fate/filter-palettegen-1 |  2 +-
 tests/ref/fate/filter-palettegen-2 |  2 +-
 3 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index ba81739d27..784e81b875 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -113,19 +113,51 @@ static int query_formats(AVFilterContext *ctx)
 
 typedef int (*cmp_func)(const void *, const void *);
 
-#define DECLARE_CMP_FUNC(name, pos) \
-static int cmp_##name(const void *pa, const void *pb)   \
-{   \
-const struct color_ref * const *a = pa; \
-const struct color_ref * const *b = pb; \
-return FFDIFFSIGN((*a)->lab.name, (*b)->lab.name);  \
+#define DECLARE_CMP_FUNC(k0, k1, k2)\
+static int cmp_##k0##k1##k2(const void *pa, const void *pb) \
+{   \
+const struct color_ref * const *a = pa; \
+const struct color_ref * const *b = pb; \
+const int c0 = FFDIFFSIGN((*a)->lab.k0, (*b)->lab.k0);  \
+const int c1 = FFDIFFSIGN((*a)->lab.k1, (*b)->lab.k1);  \
+const int c2 = FFDIFFSIGN((*a)->lab.k2, (*b)->lab.k2);  \
+return c0 ? c0 : c1 ? c1 : c2;  \
 }
 
-DECLARE_CMP_FUNC(L, 0)
-DECLARE_CMP_FUNC(a, 1)
-DECLARE_CMP_FUNC(b, 2)
+DECLARE_CMP_FUNC(L, a, b)
+DECLARE_CMP_FUNC(L, b, a)
+DECLARE_CMP_FUNC(a, L, b)
+DECLARE_CMP_FUNC(a, b, L)
+DECLARE_CMP_FUNC(b, L, a)
+DECLARE_CMP_FUNC(b, a, L)
+
+enum { ID_XYZ, ID_XZY, ID_ZXY, ID_YXZ, ID_ZYX, ID_YZX };
+static const char * const sortstr[] = { "Lab", "Lba", "bLa", "aLb", "baL", 
"abL" };
+
+static const cmp_func cmp_funcs[] = {
+[ID_XYZ] = cmp_Lab,
+[ID_XZY] = cmp_Lba,
+[ID_ZXY] = cmp_bLa,
+[ID_YXZ] = cmp_aLb,
+[ID_ZYX] = cmp_baL,
+[ID_YZX] = cmp_abL,
+};
 
-static const cmp_func cmp_funcs[] = {cmp_L, cmp_a, cmp_b};
+/*
+ * Return an identifier for the order of x, y, z (from higher to lower),
+ * preferring x over y and y over z in case of equality.
+ */
+static int sort3id(int64_t x, int64_t y, int64_t z)
+{
+if (x >= y) {
+if (y >= z) return ID_XYZ;
+if (x >= z) return ID_XZY;
+return ID_ZXY;
+}
+if (x >= z) return ID_YXZ;
+if (y >= z) return ID_YZX;
+return ID_ZYX;
+}
 
 /**
  * Simple color comparison for sorting the final palette
@@ -167,10 +199,7 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
 }
 
 /* Define the best axis candidate for cutting the box */
-box->major_axis = 0;
-if (er2[2] >= er2[0] && er2[2] >= er2[1]) box->major_axis = 2;
-if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1;
-if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
+box->major_axis = sort3id(er2[0], er2[1], er2[2]);
 
 /* The box that has the axis with the biggest error amongst all boxes will 
but cut down */
 box->cut_score = FFMAX3(er2[0], er2[1], er2[2]);
@@ -316,9 +345,9 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 int i;
 int64_t median, weight;
 
-ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
+ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %s 
(already sorted:%c) ",
 box_id, box->start, box->start + box->len - 1, box->len, 
box->weight,
-"Lab"[box->major_axis], box->sorted_by == box->major_axis ? 
'y':'n');
+sortstr[box->major_axis], box->sorted_by == box->major_axis ? 
'y':'n');
 
 /* sort the range by its major axis if it's not already sorted */
 if (box->sorted_by != box->major_axis) {
diff --git a/tests/ref/fate/filter-palettegen-1 
b/tests/ref/fate/filter-palettegen-1
index bae6b7064b..1e5c9ee002 100644
--- a/tests/ref/fate/filter-palettegen-1
+++ b/tests/ref/fate/filter-palettegen-1
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0xbb5cde01
+0,  0,  0,1, 1024, 0xa285dd77
diff --git a/tests/ref/fate/filter-palettegen-2 
b/tests/ref/fate/filter-palettegen-2
index 7217de3a92..c1fc64e13d 100644
--- a/tests/ref/fate/filter-palettegen-2
+++ b/tests/ref/fate/filter-palettegen-2
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0xfbf66e70
+0,  0,  0,1, 1024, 0xf2286e18
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org

[FFmpeg-devel] [PATCH v2 21/32] avfilter/palettegen: add a warning about supporting only sRGB

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 8 ++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 3178c43ab9..ba81739d27 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -451,9 +451,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
 AVFilterContext *ctx = inlink->dst;
 PaletteGenContext *s = ctx->priv;
-int ret = s->prev_frame ? update_histogram_diff(s->histogram, 
s->prev_frame, in)
-: update_histogram_frame(s->histogram, in);
+int ret;
+
+if (in->color_trc != AVCOL_TRC_UNSPECIFIED && in->color_trc != 
AVCOL_TRC_IEC61966_2_1)
+av_log(ctx, AV_LOG_WARNING, "The input frame is not in sRGB, colors 
may be off\n");
 
+ret = s->prev_frame ? update_histogram_diff(s->histogram, s->prev_frame, 
in)
+: update_histogram_frame(s->histogram, in);
 if (ret > 0)
 s->nb_refs += ret;
 
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 20/32] avfilter/palettegen: base box split decision on a perceptual model

2022-12-27 Thread Clément Bœsch
Similar to the change in paletteuse, we rely on a perceptual model to
decide how and where to split the box.
---
 libavfilter/Makefile   |  2 +-
 libavfilter/vf_palettegen.c| 48 --
 tests/ref/fate/filter-palettegen-1 |  2 +-
 tests/ref/fate/filter-palettegen-2 |  2 +-
 4 files changed, 29 insertions(+), 25 deletions(-)

diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index c3d13e5a26..5783be281d 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -403,7 +403,7 @@ OBJS-$(CONFIG_OVERLAY_VULKAN_FILTER) += 
vf_overlay_vulkan.o vulkan.o vul
 OBJS-$(CONFIG_OWDENOISE_FILTER)  += vf_owdenoise.o
 OBJS-$(CONFIG_PAD_FILTER)+= vf_pad.o
 OBJS-$(CONFIG_PAD_OPENCL_FILTER) += vf_pad_opencl.o opencl.o 
opencl/pad.o
-OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o
+OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o palette.o
 OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o framesync.o 
palette.o
 OBJS-$(CONFIG_PERMS_FILTER)  += f_perms.o
 OBJS-$(CONFIG_PERSPECTIVE_FILTER)+= vf_perspective.o
diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 99e4512e52..3178c43ab9 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -30,16 +30,19 @@
 #include "libavutil/intreadwrite.h"
 #include "avfilter.h"
 #include "internal.h"
+#include "palette.h"
 
 /* Reference a color and how much it's used */
 struct color_ref {
 uint32_t color;
+struct Lab lab;
 int64_t count;
 };
 
 /* Store a range of colors */
 struct range_box {
 uint32_t color; // average color
+struct Lab avg; // average color in perceptual OkLab space
 int major_axis; // best axis candidate for cutting the box
 int64_t weight; // sum of all the weights of the colors
 int64_t cut_score;  // how likely the box is to be cut down (higher 
implying more likely)
@@ -115,15 +118,14 @@ static int cmp_##name(const void *pa, const void *pb)   \
 {   \
 const struct color_ref * const *a = pa; \
 const struct color_ref * const *b = pb; \
-return   (int)((*a)->color >> (8 * (2 - (pos))) & 0xff)  \
-   - (int)((*b)->color >> (8 * (2 - (pos))) & 0xff); \
+return FFDIFFSIGN((*a)->lab.name, (*b)->lab.name);  \
 }
 
-DECLARE_CMP_FUNC(r, 0)
-DECLARE_CMP_FUNC(g, 1)
+DECLARE_CMP_FUNC(L, 0)
+DECLARE_CMP_FUNC(a, 1)
 DECLARE_CMP_FUNC(b, 2)
 
-static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
+static const cmp_func cmp_funcs[] = {cmp_L, cmp_a, cmp_b};
 
 /**
  * Simple color comparison for sorting the final palette
@@ -137,40 +139,38 @@ static int cmp_color(const void *a, const void *b)
 
 static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
 {
-int avg[3];
 int64_t er2[3] = {0};
 
 /* Compute average color */
-int64_t sr = 0, sg = 0, sb = 0;
+int64_t sL = 0, sa = 0, sb = 0;
 box->weight = 0;
 for (int i = box->start; i < box->start + box->len; i++) {
 const struct color_ref *ref = s->refs[i];
-sr += (ref->color >> 16 & 0xff) * ref->count;
-sg += (ref->color >>  8 & 0xff) * ref->count;
-sb += (ref->color   & 0xff) * ref->count;
+sL += ref->lab.L * ref->count;
+sa += ref->lab.a * ref->count;
+sb += ref->lab.b * ref->count;
 box->weight += ref->count;
 }
-avg[0] = sr / box->weight;
-avg[1] = sg / box->weight;
-avg[2] = sb / box->weight;
-box->color = 0xffU<<24 | avg[0]<<16 | avg[1]<<8 | avg[2];
+box->avg.L = sL / box->weight;
+box->avg.a = sa / box->weight;
+box->avg.b = sb / box->weight;
 
 /* Compute squared error of each color channel */
 for (int i = box->start; i < box->start + box->len; i++) {
 const struct color_ref *ref = s->refs[i];
-const int64_t dr = (int)(ref->color >> 16 & 0xff) - avg[0];
-const int64_t dg = (int)(ref->color >>  8 & 0xff) - avg[1];
-const int64_t db = (int)(ref->color   & 0xff) - avg[2];
-er2[0] += dr * dr * ref->count;
-er2[1] += dg * dg * ref->count;
+const int64_t dL = ref->lab.L - box->avg.L;
+const int64_t da = ref->lab.a - box->avg.a;
+const int64_t db = ref->lab.b - box->avg.b;
+er2[0] += dL * dL * ref->count;
+er2[1] += da * da * ref->count;
 er2[2] += db * db * ref->count;
 }
 
 /* Define the best axis candidate for cutting the box */
-box->major_axis = 1; // pick green by default (the color the eye is the 
most sensitive to)
+box->major_axis = 0;
 if (er2[2] >= er2[0] && er2[2] >= er2[1]) box->major_axis = 2;
+if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1;
 if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
-if (er2[1] >= er2[0] && er2[1] >= er2[2]) 

[FFmpeg-devel] [PATCH v2 19/32] avfilter/palettegen: switch to signed arithmetic

2022-12-27 Thread Clément Bœsch
This prevents mixed sign arithmetic (typically because we have signed
color channel differences), which has nasty side effects in C.
---
 libavfilter/vf_palettegen.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index b8db234fef..99e4512e52 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -34,14 +34,14 @@
 /* Reference a color and how much it's used */
 struct color_ref {
 uint32_t color;
-uint64_t count;
+int64_t count;
 };
 
 /* Store a range of colors */
 struct range_box {
 uint32_t color; // average color
 int major_axis; // best axis candidate for cutting the box
-uint64_t weight;// sum of all the weights of the colors
+int64_t weight; // sum of all the weights of the colors
 int64_t cut_score;  // how likely the box is to be cut down (higher 
implying more likely)
 int start;  // index in PaletteGenContext->refs
 int len;// number of referenced colors
@@ -141,7 +141,7 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
 int64_t er2[3] = {0};
 
 /* Compute average color */
-uint64_t sr = 0, sg = 0, sb = 0;
+int64_t sr = 0, sg = 0, sb = 0;
 box->weight = 0;
 for (int i = box->start; i < box->start + box->len; i++) {
 const struct color_ref *ref = s->refs[i];
@@ -314,7 +314,7 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 
 while (box && box->len > 1) {
 int i;
-uint64_t median, weight;
+int64_t median, weight;
 
 ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
 box_id, box->start, box->start + box->len - 1, box->len, 
box->weight,
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 18/32] avfilter/palettegen: rename local variable box_weight to weight

2022-12-27 Thread Clément Bœsch
This variable is used only for the running weight (used to reach the
target median). The places where we actually need the box weight are
changed to use box->weight.
---
 libavfilter/vf_palettegen.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index ad21882df3..b8db234fef 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -314,12 +314,10 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 
 while (box && box->len > 1) {
 int i;
-uint64_t median, box_weight;
-
-box_weight = box->weight;
+uint64_t median, weight;
 
 ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
-box_id, box->start, box->start + box->len - 1, box->len, 
box_weight,
+box_id, box->start, box->start + box->len - 1, box->len, 
box->weight,
 "rgb"[box->major_axis], box->sorted_by == box->major_axis ? 
'y':'n');
 
 /* sort the range by its major axis if it's not already sorted */
@@ -330,16 +328,16 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 }
 
 /* locate the median where to split */
-median = (box_weight + 1) >> 1;
-box_weight = 0;
+median = (box->weight + 1) >> 1;
+weight = 0;
 /* if you have 2 boxes, the maximum is actually #0: you must have at
  * least 1 color on each side of the split, hence the -2 */
 for (i = box->start; i < box->start + box->len - 2; i++) {
-box_weight += s->refs[i]->count;
-if (box_weight > median)
+weight += s->refs[i]->count;
+if (weight > median)
 break;
 }
-ff_dlog(ctx, "split @ i=%-6d with w=%-6"PRIu64" 
(target=%6"PRIu64")\n", i, box_weight, median);
+ff_dlog(ctx, "split @ i=%-6d with w=%-6"PRIu64" 
(target=%6"PRIu64")\n", i, weight, median);
 split_box(s, box, i);
 
 box_id = get_next_box_id_to_split(s);
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 17/32] avfilter/palettegen: misc cosmetics

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 36f0a976d9..ad21882df3 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -132,7 +132,7 @@ static int cmp_color(const void *a, const void *b)
 {
 const struct range_box *box1 = a;
 const struct range_box *box2 = b;
-return FFDIFFSIGN(box1->color , box2->color);
+return FFDIFFSIGN(box1->color, box2->color);
 }
 
 static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
@@ -188,7 +188,7 @@ static int get_next_box_id_to_split(PaletteGenContext *s)
 return -1;
 
 for (box_id = 0; box_id < s->nb_boxes; box_id++) {
-struct range_box *box = >boxes[box_id];
+const struct range_box *box = >boxes[box_id];
 if (s->boxes[box_id].len >= 2 && box->cut_score > max_score) {
 best_box_id = box_id;
 max_score = box->cut_score;
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 16/32] avfilter/palettegen: compute average color within compute_box_stats()

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 30 +-
 1 file changed, 1 insertion(+), 29 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 00b5f88c49..36f0a976d9 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -153,6 +153,7 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
 avg[0] = sr / box->weight;
 avg[1] = sg / box->weight;
 avg[2] = sb / box->weight;
+box->color = 0xffU<<24 | avg[0]<<16 | avg[1]<<8 | avg[2];
 
 /* Compute squared error of each color channel */
 for (int i = box->start; i < box->start + box->len; i++) {
@@ -196,32 +197,6 @@ static int get_next_box_id_to_split(PaletteGenContext *s)
 return best_box_id;
 }
 
-/**
- * Get the 32-bit average color for the range of RGB colors enclosed in the
- * specified box. Takes into account the weight of each color.
- */
-static uint32_t get_avg_color(struct color_ref * const *refs,
-  const struct range_box *box)
-{
-int i;
-const int n = box->len;
-uint64_t r = 0, g = 0, b = 0, div = 0;
-
-for (i = 0; i < n; i++) {
-const struct color_ref *ref = refs[box->start + i];
-r += (ref->color >> 16 & 0xff) * ref->count;
-g += (ref->color >>  8 & 0xff) * ref->count;
-b += (ref->color   & 0xff) * ref->count;
-div += ref->count;
-}
-
-r = r / div;
-g = g / div;
-b = b / div;
-
-return 0xffU<<24 | r<<16 | g<<8 | b;
-}
-
 /**
  * Split given box in two at position n. The original box becomes the left part
  * of the split, and the new index box is the right part.
@@ -237,8 +212,6 @@ static void split_box(PaletteGenContext *s, struct 
range_box *box, int n)
 av_assert0(box->len >= 1);
 av_assert0(new_box->len >= 1);
 
-box->color = get_avg_color(s->refs, box);
-new_box->color = get_avg_color(s->refs, new_box);
 compute_box_stats(s, box);
 compute_box_stats(s, new_box);
 }
@@ -336,7 +309,6 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 box = >boxes[box_id];
 box->len = s->nb_refs;
 box->sorted_by = -1;
-box->color = get_avg_color(s->refs, box);
 compute_box_stats(s, box);
 s->nb_boxes = 1;
 
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 15/32] avfilter/palettegen: change cut score from ∑e² to max e²

2022-12-27 Thread Clément Bœsch
This is following the results from personal research¹.

¹: https://github.com/ubitux/research/tree/main/color-quantization#results
---
 libavfilter/vf_palettegen.c| 3 ++-
 tests/ref/fate/filter-palettegen-1 | 2 +-
 tests/ref/fate/filter-palettegen-2 | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 7ecb1211ba..00b5f88c49 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -171,7 +171,8 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
 if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
 if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1; // prefer 
green again
 
-box->cut_score = er2[0] + er2[1] + er2[2];
+/* The box that has the axis with the biggest error amongst all boxes will 
but cut down */
+box->cut_score = FFMAX3(er2[0], er2[1], er2[2]);
 }
 
 /**
diff --git a/tests/ref/fate/filter-palettegen-1 
b/tests/ref/fate/filter-palettegen-1
index 278d831846..57be338b42 100644
--- a/tests/ref/fate/filter-palettegen-1
+++ b/tests/ref/fate/filter-palettegen-1
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0x394ee723
+0,  0,  0,1, 1024, 0x21c6e6c4
diff --git a/tests/ref/fate/filter-palettegen-2 
b/tests/ref/fate/filter-palettegen-2
index e9bc635c81..bcdf54af95 100644
--- a/tests/ref/fate/filter-palettegen-2
+++ b/tests/ref/fate/filter-palettegen-2
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0xc54d773d
+0,  0,  0,1, 1024, 0x630d76b1
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 14/32] avfilter/palettegen: rename variance to cut_score

2022-12-27 Thread Clément Bœsch
"Variance" wasn't exactly the correct word; "cut score" is more
agnostic, which will be useful when changing the algorithm in the next
commit.
---
 libavfilter/vf_palettegen.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index ca1e02444c..7ecb1211ba 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -42,7 +42,7 @@ struct range_box {
 uint32_t color; // average color
 int major_axis; // best axis candidate for cutting the box
 uint64_t weight;// sum of all the weights of the colors
-int64_t variance;   // overall variance of the box (how much the colors 
are spread)
+int64_t cut_score;  // how likely the box is to be cut down (higher 
implying more likely)
 int start;  // index in PaletteGenContext->refs
 int len;// number of referenced colors
 int sorted_by;  // whether range of colors is sorted by red (0), green 
(1) or blue (2)
@@ -171,25 +171,25 @@ static void compute_box_stats(PaletteGenContext *s, 
struct range_box *box)
 if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
 if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1; // prefer 
green again
 
-box->variance = er2[0] + er2[1] + er2[2];
+box->cut_score = er2[0] + er2[1] + er2[2];
 }
 
 /**
- * Find the next box to split: pick the one with the highest variance
+ * Find the next box to split: pick the one with the highest cut score
  */
 static int get_next_box_id_to_split(PaletteGenContext *s)
 {
 int box_id, best_box_id = -1;
-int64_t max_variance = -1;
+int64_t max_score = -1;
 
 if (s->nb_boxes == s->max_colors - s->reserve_transparent)
 return -1;
 
 for (box_id = 0; box_id < s->nb_boxes; box_id++) {
 struct range_box *box = >boxes[box_id];
-if (s->boxes[box_id].len >= 2 && box->variance > max_variance) {
+if (s->boxes[box_id].len >= 2 && box->cut_score > max_score) {
 best_box_id = box_id;
-max_variance = box->variance;
+max_score = box->cut_score;
 }
 }
 return best_box_id;
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 13/32] avfilter/palettegen: always compute the box variance

2022-12-27 Thread Clément Bœsch
The variance computation is simple enough now (since we can use the axis
squared errors) that it doesn't need to have a complex lazy computation
logic.
---
 libavfilter/vf_palettegen.c | 42 -
 1 file changed, 9 insertions(+), 33 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index aa0c8fdc5b..ca1e02444c 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -135,16 +135,6 @@ static int cmp_color(const void *a, const void *b)
 return FFDIFFSIGN(box1->color , box2->color);
 }
 
-static av_always_inline int diff(const uint32_t a, const uint32_t b)
-{
-const uint8_t c1[] = {a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff};
-const uint8_t c2[] = {b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff};
-const int dr = c1[0] - c2[0];
-const int dg = c1[1] - c2[1];
-const int db = c1[2] - c2[2];
-return dr*dr + dg*dg + db*db;
-}
-
 static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
 {
 int avg[3];
@@ -180,6 +170,8 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
 if (er2[2] >= er2[0] && er2[2] >= er2[1]) box->major_axis = 2;
 if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
 if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1; // prefer 
green again
+
+box->variance = er2[0] + er2[1] + er2[2];
 }
 
 /**
@@ -187,7 +179,7 @@ static void compute_box_stats(PaletteGenContext *s, struct 
range_box *box)
  */
 static int get_next_box_id_to_split(PaletteGenContext *s)
 {
-int box_id, i, best_box_id = -1;
+int box_id, best_box_id = -1;
 int64_t max_variance = -1;
 
 if (s->nb_boxes == s->max_colors - s->reserve_transparent)
@@ -195,24 +187,9 @@ static int get_next_box_id_to_split(PaletteGenContext *s)
 
 for (box_id = 0; box_id < s->nb_boxes; box_id++) {
 struct range_box *box = >boxes[box_id];
-
-if (s->boxes[box_id].len >= 2) {
-
-if (box->variance == -1) {
-int64_t variance = 0;
-
-for (i = 0; i < box->len; i++) {
-const struct color_ref *ref = s->refs[box->start + i];
-variance += diff(ref->color, box->color) * ref->count;
-}
-box->variance = variance;
-}
-if (box->variance > max_variance) {
-best_box_id = box_id;
-max_variance = box->variance;
-}
-} else {
-box->variance = -1;
+if (s->boxes[box_id].len >= 2 && box->variance > max_variance) {
+best_box_id = box_id;
+max_variance = box->variance;
 }
 }
 return best_box_id;
@@ -261,8 +238,8 @@ static void split_box(PaletteGenContext *s, struct 
range_box *box, int n)
 
 box->color = get_avg_color(s->refs, box);
 new_box->color = get_avg_color(s->refs, new_box);
-box->variance = -1;
-new_box->variance = -1;
+compute_box_stats(s, box);
+compute_box_stats(s, new_box);
 }
 
 /**
@@ -359,14 +336,13 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 box->len = s->nb_refs;
 box->sorted_by = -1;
 box->color = get_avg_color(s->refs, box);
-box->variance = -1;
+compute_box_stats(s, box);
 s->nb_boxes = 1;
 
 while (box && box->len > 1) {
 int i;
 uint64_t median, box_weight;
 
-compute_box_stats(s, box);
 box_weight = box->weight;
 
 ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 12/32] avfilter/palettegen: use box->major_axis without intermediate variable

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index ed1448755c..aa0c8fdc5b 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -363,22 +363,21 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 s->nb_boxes = 1;
 
 while (box && box->len > 1) {
-int i, longest;
+int i;
 uint64_t median, box_weight;
 
 compute_box_stats(s, box);
-longest = box->major_axis;
 box_weight = box->weight;
 
 ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
 box_id, box->start, box->start + box->len - 1, box->len, 
box_weight,
-"rgb"[longest], box->sorted_by == longest ? 'y':'n');
+"rgb"[box->major_axis], box->sorted_by == box->major_axis ? 
'y':'n');
 
-/* sort the range by its longest axis if it's not already sorted */
-if (box->sorted_by != longest) {
-cmp_func cmpf = cmp_funcs[longest];
+/* sort the range by its major axis if it's not already sorted */
+if (box->sorted_by != box->major_axis) {
+cmp_func cmpf = cmp_funcs[box->major_axis];
 AV_QSORT(>refs[box->start], box->len, const struct color_ref *, 
cmpf);
-box->sorted_by = longest;
+box->sorted_by = box->major_axis;
 }
 
 /* locate the median where to split */
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 11/32] avfilter/palettegen: define the best axis to cut using the squared error

2022-12-27 Thread Clément Bœsch
This is following the results from personal research¹.

¹: https://github.com/ubitux/research/tree/main/color-quantization#results
---
 libavfilter/vf_palettegen.c| 42 ++
 tests/ref/fate/filter-palettegen-1 |  2 +-
 tests/ref/fate/filter-palettegen-2 |  2 +-
 3 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index a047c75599..ed1448755c 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -147,31 +147,39 @@ static av_always_inline int diff(const uint32_t a, const 
uint32_t b)
 
 static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
 {
-int rr, gr, br;
+int avg[3];
+int64_t er2[3] = {0};
 
-/* compute the box weight (sum all the weights of the colors in the
- * range) and its boundings */
-uint8_t min[3] = {0xff, 0xff, 0xff};
-uint8_t max[3] = {0x00, 0x00, 0x00};
+/* Compute average color */
+uint64_t sr = 0, sg = 0, sb = 0;
 box->weight = 0;
 for (int i = box->start; i < box->start + box->len; i++) {
 const struct color_ref *ref = s->refs[i];
-const uint32_t rgb = ref->color;
-const uint8_t r = rgb >> 16 & 0xff, g = rgb >> 8 & 0xff, b = rgb & 
0xff;
-min[0] = FFMIN(r, min[0]), max[0] = FFMAX(r, max[0]);
-min[1] = FFMIN(g, min[1]), max[1] = FFMAX(g, max[1]);
-min[2] = FFMIN(b, min[2]), max[2] = FFMAX(b, max[2]);
+sr += (ref->color >> 16 & 0xff) * ref->count;
+sg += (ref->color >>  8 & 0xff) * ref->count;
+sb += (ref->color   & 0xff) * ref->count;
 box->weight += ref->count;
 }
+avg[0] = sr / box->weight;
+avg[1] = sg / box->weight;
+avg[2] = sb / box->weight;
 
-/* define the axis to sort by according to the widest range of colors */
-rr = max[0] - min[0];
-gr = max[1] - min[1];
-br = max[2] - min[2];
+/* Compute squared error of each color channel */
+for (int i = box->start; i < box->start + box->len; i++) {
+const struct color_ref *ref = s->refs[i];
+const int64_t dr = (int)(ref->color >> 16 & 0xff) - avg[0];
+const int64_t dg = (int)(ref->color >>  8 & 0xff) - avg[1];
+const int64_t db = (int)(ref->color   & 0xff) - avg[2];
+er2[0] += dr * dr * ref->count;
+er2[1] += dg * dg * ref->count;
+er2[2] += db * db * ref->count;
+}
+
+/* Define the best axis candidate for cutting the box */
 box->major_axis = 1; // pick green by default (the color the eye is the 
most sensitive to)
-if (br >= rr && br >= gr) box->major_axis = 2;
-if (rr >= gr && rr >= br) box->major_axis = 0;
-if (gr >= rr && gr >= br) box->major_axis = 1; // prefer green again
+if (er2[2] >= er2[0] && er2[2] >= er2[1]) box->major_axis = 2;
+if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
+if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1; // prefer 
green again
 }
 
 /**
diff --git a/tests/ref/fate/filter-palettegen-1 
b/tests/ref/fate/filter-palettegen-1
index bebfd24e19..278d831846 100644
--- a/tests/ref/fate/filter-palettegen-1
+++ b/tests/ref/fate/filter-palettegen-1
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0x3395ef5a
+0,  0,  0,1, 1024, 0x394ee723
diff --git a/tests/ref/fate/filter-palettegen-2 
b/tests/ref/fate/filter-palettegen-2
index 9abec0fe8e..e9bc635c81 100644
--- a/tests/ref/fate/filter-palettegen-2
+++ b/tests/ref/fate/filter-palettegen-2
@@ -3,4 +3,4 @@
 #codec_id 0: rawvideo
 #dimensions 0: 16x16
 #sar 0: 1/1
-0,  0,  0,1, 1024, 0x23e072c8
+0,  0,  0,1, 1024, 0xc54d773d
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 10/32] avfilter/palettegen: move box stats computation to a dedicated function

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 64 ++---
 1 file changed, 38 insertions(+), 26 deletions(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index bea3292796..a047c75599 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -40,6 +40,8 @@ struct color_ref {
 /* Store a range of colors */
 struct range_box {
 uint32_t color; // average color
+int major_axis; // best axis candidate for cutting the box
+uint64_t weight;// sum of all the weights of the colors
 int64_t variance;   // overall variance of the box (how much the colors 
are spread)
 int start;  // index in PaletteGenContext->refs
 int len;// number of referenced colors
@@ -143,6 +145,35 @@ static av_always_inline int diff(const uint32_t a, const 
uint32_t b)
 return dr*dr + dg*dg + db*db;
 }
 
+static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
+{
+int rr, gr, br;
+
+/* compute the box weight (sum all the weights of the colors in the
+ * range) and its boundings */
+uint8_t min[3] = {0xff, 0xff, 0xff};
+uint8_t max[3] = {0x00, 0x00, 0x00};
+box->weight = 0;
+for (int i = box->start; i < box->start + box->len; i++) {
+const struct color_ref *ref = s->refs[i];
+const uint32_t rgb = ref->color;
+const uint8_t r = rgb >> 16 & 0xff, g = rgb >> 8 & 0xff, b = rgb & 
0xff;
+min[0] = FFMIN(r, min[0]), max[0] = FFMAX(r, max[0]);
+min[1] = FFMIN(g, min[1]), max[1] = FFMAX(g, max[1]);
+min[2] = FFMIN(b, min[2]), max[2] = FFMAX(b, max[2]);
+box->weight += ref->count;
+}
+
+/* define the axis to sort by according to the widest range of colors */
+rr = max[0] - min[0];
+gr = max[1] - min[1];
+br = max[2] - min[2];
+box->major_axis = 1; // pick green by default (the color the eye is the 
most sensitive to)
+if (br >= rr && br >= gr) box->major_axis = 2;
+if (rr >= gr && rr >= br) box->major_axis = 0;
+if (gr >= rr && gr >= br) box->major_axis = 1; // prefer green again
+}
+
 /**
  * Find the next box to split: pick the one with the highest variance
  */
@@ -324,35 +355,16 @@ static AVFrame *get_palette_frame(AVFilterContext *ctx)
 s->nb_boxes = 1;
 
 while (box && box->len > 1) {
-int i, rr, gr, br, longest;
-uint64_t median, box_weight = 0;
-
-/* compute the box weight (sum all the weights of the colors in the
- * range) and its boundings */
-uint8_t min[3] = {0xff, 0xff, 0xff};
-uint8_t max[3] = {0x00, 0x00, 0x00};
-for (i = box->start; i < box->start + box->len; i++) {
-const struct color_ref *ref = s->refs[i];
-const uint32_t rgb = ref->color;
-const uint8_t r = rgb >> 16 & 0xff, g = rgb >> 8 & 0xff, b = rgb & 
0xff;
-min[0] = FFMIN(r, min[0]), max[0] = FFMAX(r, max[0]);
-min[1] = FFMIN(g, min[1]), max[1] = FFMAX(g, max[1]);
-min[2] = FFMIN(b, min[2]), max[2] = FFMAX(b, max[2]);
-box_weight += ref->count;
-}
+int i, longest;
+uint64_t median, box_weight;
 
-/* define the axis to sort by according to the widest range of colors 
*/
-rr = max[0] - min[0];
-gr = max[1] - min[1];
-br = max[2] - min[2];
-longest = 1; // pick green by default (the color the eye is the most 
sensitive to)
-if (br >= rr && br >= gr) longest = 2;
-if (rr >= gr && rr >= br) longest = 0;
-if (gr >= rr && gr >= br) longest = 1; // prefer green again
+compute_box_stats(s, box);
+longest = box->major_axis;
+box_weight = box->weight;
 
-ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" ranges:[%2x 
%2x %2x] sort by %c (already sorted:%c) ",
+ff_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" sort by %c 
(already sorted:%c) ",
 box_id, box->start, box->start + box->len - 1, box->len, 
box_weight,
-rr, gr, br, "rgb"[longest], box->sorted_by == longest ? 
'y':'n');
+"rgb"[longest], box->sorted_by == longest ? 'y':'n');
 
 /* sort the range by its longest axis if it's not already sorted */
 if (box->sorted_by != longest) {
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 09/32] avfilter/paletteuse: switch to a perceptual model

2022-12-27 Thread Clément Bœsch
Now the selection of the color is based on a distance built around human
perception of color instead of the unreliable sRGB triplet one.
---
 libavfilter/Makefile|   2 +-
 libavfilter/vf_paletteuse.c | 181 ++--
 tests/ref/fate/filter-paletteuse-bayer  | 142 +++
 tests/ref/fate/filter-paletteuse-bayer0 | 142 +++
 tests/ref/fate/filter-paletteuse-nodither   | 142 +++
 tests/ref/fate/filter-paletteuse-sierra2_4a | 142 +++
 6 files changed, 378 insertions(+), 373 deletions(-)

diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index cb41ccc622..c3d13e5a26 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -404,7 +404,7 @@ OBJS-$(CONFIG_OWDENOISE_FILTER)  += 
vf_owdenoise.o
 OBJS-$(CONFIG_PAD_FILTER)+= vf_pad.o
 OBJS-$(CONFIG_PAD_OPENCL_FILTER) += vf_pad_opencl.o opencl.o 
opencl/pad.o
 OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o
-OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o framesync.o
+OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o framesync.o 
palette.o
 OBJS-$(CONFIG_PERMS_FILTER)  += f_perms.o
 OBJS-$(CONFIG_PERSPECTIVE_FILTER)+= vf_perspective.o
 OBJS-$(CONFIG_PHASE_FILTER)  += vf_phase.o
diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index 0861a70a0b..3af121b1eb 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -32,6 +32,7 @@
 #include "filters.h"
 #include "framesync.h"
 #include "internal.h"
+#include "palette.h"
 
 enum dithering_mode {
 DITHERING_NONE,
@@ -56,8 +57,13 @@ enum diff_mode {
 NB_DIFF_MODE
 };
 
+struct color_info {
+uint32_t srgb;
+int32_t lab[3];
+};
+
 struct color_node {
-uint32_t val;
+struct color_info c;
 uint8_t palette_id;
 int split;
 int left_id, right_id;
@@ -162,25 +168,32 @@ static av_always_inline uint32_t dither_color(uint32_t 
px, int er, int eg,
  | av_clip_uint8((px   & 0xff) + ((eb * scale) / (1<> 24, a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff};
-const uint8_t c2[] = {b >> 24, b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff};
-const int dr = c1[1] - c2[1];
-const int dg = c1[2] - c2[2];
-const int db = c1[3] - c2[3];
-
-if (c1[0] < trans_thresh && c2[0] < trans_thresh) {
+const uint8_t alpha_a = a->srgb >> 24;
+const uint8_t alpha_b = b->srgb >> 24;
+
+if (alpha_a < trans_thresh && alpha_b < trans_thresh) {
 return 0;
-} else if (c1[0] >= trans_thresh && c2[0] >= trans_thresh) {
-return dr*dr + dg*dg + db*db;
+} else if (alpha_a >= trans_thresh && alpha_b >= trans_thresh) {
+const int64_t dL = a->lab[0] - b->lab[0];
+const int64_t da = a->lab[1] - b->lab[1];
+const int64_t db = a->lab[2] - b->lab[2];
+const int64_t ret = dL*dL + da*da + db*db;
+return FFMIN(ret, INT32_MAX - 1);
 } else {
-return 255*255 + 255*255 + 255*255;
+return INT32_MAX - 1;
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const uint32_t target, const int trans_thresh)
+static struct color_info get_color_from_srgb(uint32_t srgb)
+{
+const struct Lab lab = ff_srgb_u8_to_oklab_int(srgb);
+struct color_info ret = {.srgb=srgb, .lab={lab.L, lab.a, lab.b}};
+return ret;
+}
+
+static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const struct color_info *target, const int trans_thresh)
 {
 int i, pal_id = -1, min_dist = INT_MAX;
 
@@ -188,7 +201,8 @@ static av_always_inline uint8_t 
colormap_nearest_bruteforce(const uint32_t *pale
 const uint32_t c = palette[i];
 
 if (c >> 24 >= trans_thresh) { // ignore transparent entry
-const int d = diff(palette[i], target, trans_thresh);
+const struct color_info pal_color = 
get_color_from_srgb(palette[i]);
+const int d = diff(_color, target, trans_thresh);
 if (d < min_dist) {
 pal_id = i;
 min_dist = d;
@@ -206,14 +220,13 @@ struct nearest_color {
 
 static void colormap_nearest_node(const struct color_node *map,
   const int node_pos,
-  const uint32_t target,
+  const struct color_info *target,
   const int trans_thresh,
   struct nearest_color *nearest)
 {
 const struct color_node *kd = map + node_pos;
-const int shift = (2 - kd->split) * 8;
-int dx, nearer_kd_id, further_kd_id;
-const uint32_t current = kd->val;
+int nearer_kd_id, further_kd_id;
+const struct color_info *current = >c;
 const int current_to_target = diff(target, current, trans_thresh);
 
 if (current_to_target < nearest->dist_sqd) {
@@ -222,7 

[FFmpeg-devel] [PATCH v2 05/32] avfilter/paletteuse: switch from u8[4] to u32 for color code

2022-12-27 Thread Clément Bœsch
This change simplifies the code quite a bit and make it consistent with
how it's done in palettegen.
---
 libavfilter/vf_paletteuse.c | 98 -
 1 file changed, 41 insertions(+), 57 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index f9d8a1cdfc..fb4016b11c 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -57,7 +57,7 @@ enum diff_mode {
 };
 
 struct color_node {
-uint8_t val[4];
+uint32_t val;
 uint8_t palette_id;
 int split;
 int left_id, right_id;
@@ -162,9 +162,11 @@ static av_always_inline uint32_t dither_color(uint32_t px, 
int er, int eg,
  | av_clip_uint8((px   & 0xff) + ((eb * scale) / (1<> 24, a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff};
+const uint8_t c2[] = {b >> 24, b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff};
 const int dr = c1[1] - c2[1];
 const int dg = c1[2] - c2[2];
 const int db = c1[3] - c2[3];
@@ -178,7 +180,7 @@ static av_always_inline int diff(const uint8_t *c1, const 
uint8_t *c2, const int
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const uint8_t *argb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t 
*palette, const uint32_t argb, const int trans_thresh)
 {
 int i, pal_id = -1, min_dist = INT_MAX;
 
@@ -186,13 +188,7 @@ static av_always_inline uint8_t 
colormap_nearest_bruteforce(const uint32_t *pale
 const uint32_t c = palette[i];
 
 if (c >> 24 >= trans_thresh) { // ignore transparent entry
-const uint8_t palargb[] = {
-palette[i]>>24,
-palette[i]>>16 & 0xff,
-palette[i]>> 8 & 0xff,
-palette[i] & 0xff,
-};
-const int d = diff(palargb, argb, trans_thresh);
+const int d = diff(palette[i], argb, trans_thresh);
 if (d < min_dist) {
 pal_id = i;
 min_dist = d;
@@ -210,14 +206,14 @@ struct nearest_color {
 
 static void colormap_nearest_node(const struct color_node *map,
   const int node_pos,
-  const uint8_t *target,
+  const uint32_t target,
   const int trans_thresh,
   struct nearest_color *nearest)
 {
 const struct color_node *kd = map + node_pos;
-const int s = kd->split;
+const int shift = (3 - kd->split) * 8;
 int dx, nearer_kd_id, further_kd_id;
-const uint8_t *current = kd->val;
+const uint32_t current = kd->val;
 const int current_to_target = diff(target, current, trans_thresh);
 
 if (current_to_target < nearest->dist_sqd) {
@@ -226,7 +222,7 @@ static void colormap_nearest_node(const struct color_node 
*map,
 }
 
 if (kd->left_id != -1 || kd->right_id != -1) {
-dx = target[s] - current[s];
+dx = (int)(target>>shift & 0xff) - (int)(current>>shift & 0xff);
 
 if (dx <= 0) nearer_kd_id = kd->left_id,  further_kd_id = kd->right_id;
 else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
@@ -239,7 +235,7 @@ static void colormap_nearest_node(const struct color_node 
*map,
 }
 }
 
-static av_always_inline uint8_t colormap_nearest_recursive(const struct 
color_node *node, const uint8_t *rgb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_recursive(const struct 
color_node *node, const uint8_t rgb, const int trans_thresh)
 {
 struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
 colormap_nearest_node(node, 0, rgb, trans_thresh, );
@@ -251,7 +247,7 @@ struct stack_node {
 int dx2;
 };
 
-static av_always_inline uint8_t colormap_nearest_iterative(const struct 
color_node *root, const uint8_t *target, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_iterative(const struct 
color_node *root, const uint32_t target, const int trans_thresh)
 {
 int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
 struct stack_node nodes[16];
@@ -260,7 +256,7 @@ static av_always_inline uint8_t 
colormap_nearest_iterative(const struct color_no
 for (;;) {
 
 const struct color_node *kd = [cur_color_id];
-const uint8_t *current = kd->val;
+const uint32_t current = kd->val;
 const int current_to_target = diff(target, current, trans_thresh);
 
 /* Compare current color node to the target and update our best node if
@@ -274,8 +270,8 @@ static av_always_inline uint8_t 
colormap_nearest_iterative(const struct color_no
 
 /* Check if it's not a leaf */
 if (kd->left_id != -1 || kd->right_id != -1) {
-const int split = kd->split;
-const int dx = target[split] - current[split];
+const int shift = (3 - kd->split) * 8;
+const int dx = 

[FFmpeg-devel] [PATCH v2 04/32] avfilter/palette{gen, use}: add palette utils

2022-12-27 Thread Clément Bœsch
These color management helpers will be shared by palettegen and
paletteuse in the following commits.

Note that it probably makes sense to share at least the sRGB/linear
functions with other filters at some point.

More information on OkLab can be found here: 
https://bottosson.github.io/posts/oklab/

For the arithmetic integer version, see:
http://blog.pkh.me/p/38-porting-oklab-colorspace-to-integer-arithmetic.html
and https://github.com/ubitux/oklab-int
---
 libavfilter/palette.c | 210 ++
 libavfilter/palette.h |  58 
 2 files changed, 268 insertions(+)
 create mode 100644 libavfilter/palette.c
 create mode 100644 libavfilter/palette.h

diff --git a/libavfilter/palette.c b/libavfilter/palette.c
new file mode 100644
index 00..03e48fc71e
--- /dev/null
+++ b/libavfilter/palette.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2020 Björn Ottosson
+ * Copyright (c) 2022 Clément Bœsch 
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libavutil/common.h"
+#include "palette.h"
+
+#define K ((1 << 16) - 1)
+#define K2 ((int64_t)K*K)
+#define P ((1 << 9) - 1)
+
+/**
+ * Table mapping formula:
+ *   f(x) = x < 0.04045 ? x/12.92 : ((x+0.055)/1.055)^2.4  (sRGB EOTF)
+ * Where x is the normalized index in the table and f(x) the value in the 
table.
+ * f(x) is remapped to [0;K] and rounded.
+ */
+static const uint16_t srgb2linear[256] = {
+0x, 0x0014, 0x0028, 0x003c, 0x0050, 0x0063, 0x0077, 0x008b,
+0x009f, 0x00b3, 0x00c7, 0x00db, 0x00f1, 0x0108, 0x0120, 0x0139,
+0x0154, 0x016f, 0x018c, 0x01ab, 0x01ca, 0x01eb, 0x020e, 0x0232,
+0x0257, 0x027d, 0x02a5, 0x02ce, 0x02f9, 0x0325, 0x0353, 0x0382,
+0x03b3, 0x03e5, 0x0418, 0x044d, 0x0484, 0x04bc, 0x04f6, 0x0532,
+0x056f, 0x05ad, 0x05ed, 0x062f, 0x0673, 0x06b8, 0x06fe, 0x0747,
+0x0791, 0x07dd, 0x082a, 0x087a, 0x08ca, 0x091d, 0x0972, 0x09c8,
+0x0a20, 0x0a79, 0x0ad5, 0x0b32, 0x0b91, 0x0bf2, 0x0c55, 0x0cba,
+0x0d20, 0x0d88, 0x0df2, 0x0e5e, 0x0ecc, 0x0f3c, 0x0fae, 0x1021,
+0x1097, 0x110e, 0x1188, 0x1203, 0x1280, 0x1300, 0x1381, 0x1404,
+0x1489, 0x1510, 0x159a, 0x1625, 0x16b2, 0x1741, 0x17d3, 0x1866,
+0x18fb, 0x1993, 0x1a2c, 0x1ac8, 0x1b66, 0x1c06, 0x1ca7, 0x1d4c,
+0x1df2, 0x1e9a, 0x1f44, 0x1ff1, 0x20a0, 0x2150, 0x2204, 0x22b9,
+0x2370, 0x242a, 0x24e5, 0x25a3, 0x2664, 0x2726, 0x27eb, 0x28b1,
+0x297b, 0x2a46, 0x2b14, 0x2be3, 0x2cb6, 0x2d8a, 0x2e61, 0x2f3a,
+0x3015, 0x30f2, 0x31d2, 0x32b4, 0x3399, 0x3480, 0x3569, 0x3655,
+0x3742, 0x3833, 0x3925, 0x3a1a, 0x3b12, 0x3c0b, 0x3d07, 0x3e06,
+0x3f07, 0x400a, 0x4110, 0x4218, 0x4323, 0x4430, 0x453f, 0x4651,
+0x4765, 0x487c, 0x4995, 0x4ab1, 0x4bcf, 0x4cf0, 0x4e13, 0x4f39,
+0x5061, 0x518c, 0x52b9, 0x53e9, 0x551b, 0x5650, 0x5787, 0x58c1,
+0x59fe, 0x5b3d, 0x5c7e, 0x5dc2, 0x5f09, 0x6052, 0x619e, 0x62ed,
+0x643e, 0x6591, 0x66e8, 0x6840, 0x699c, 0x6afa, 0x6c5b, 0x6dbe,
+0x6f24, 0x708d, 0x71f8, 0x7366, 0x74d7, 0x764a, 0x77c0, 0x7939,
+0x7ab4, 0x7c32, 0x7db3, 0x7f37, 0x80bd, 0x8246, 0x83d1, 0x855f,
+0x86f0, 0x8884, 0x8a1b, 0x8bb4, 0x8d50, 0x8eef, 0x9090, 0x9235,
+0x93dc, 0x9586, 0x9732, 0x98e2, 0x9a94, 0x9c49, 0x9e01, 0x9fbb,
+0xa179, 0xa339, 0xa4fc, 0xa6c2, 0xa88b, 0xaa56, 0xac25, 0xadf6,
+0xafca, 0xb1a1, 0xb37b, 0xb557, 0xb737, 0xb919, 0xbaff, 0xbce7,
+0xbed2, 0xc0c0, 0xc2b1, 0xc4a5, 0xc69c, 0xc895, 0xca92, 0xcc91,
+0xce94, 0xd099, 0xd2a1, 0xd4ad, 0xd6bb, 0xd8cc, 0xdae0, 0xdcf7,
+0xdf11, 0xe12e, 0xe34e, 0xe571, 0xe797, 0xe9c0, 0xebec, 0xee1b,
+0xf04d, 0xf282, 0xf4ba, 0xf6f5, 0xf933, 0xfb74, 0xfdb8, 0x,
+};
+
+/**
+ * Table mapping formula:
+ *   f(x) = x < 0.0031308 ? x*12.92 : 1.055*x^(1/2.4)-0.055  (sRGB OETF)
+ * Where x is the normalized index in the table and f(x) the value in the 
table.
+ * f(x) is remapped to [0;0xff] and rounded.
+ *
+ * Since a 16-bit table is too large, we reduce its precision to 9-bit.
+ */
+static const uint8_t linear2srgb[P + 1] = {
+0x00, 0x06, 0x0d, 0x12, 0x16, 0x19, 0x1c, 0x1f, 0x22, 0x24, 0x26, 0x28, 
0x2a, 0x2c, 0x2e, 0x30,
+0x32, 0x33, 0x35, 0x36, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x41, 
0x42, 0x43, 0x45, 0x46,
+0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 

[FFmpeg-devel] [PATCH v2 03/32] avfilter/palette{gen, use}: simplify a few alpha masks

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_paletteuse.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index cb18329bb7..f9d8a1cdfc 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -156,7 +156,7 @@ static int query_formats(AVFilterContext *ctx)
 static av_always_inline uint32_t dither_color(uint32_t px, int er, int eg,
   int eb, int scale, int shift)
 {
-returnpx >> 24<< 24
+return (px & 0xff00)
  | av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<>  8 & 0xff) + ((eg * scale) / (1<> 24 >= trans_thresh) { // ignore transparent entry
 const uint8_t palargb[] = {
-palette[i]>>24 & 0xff,
+palette[i]>>24,
 palette[i]>>16 & 0xff,
 palette[i]>> 8 & 0xff,
 palette[i] & 0xff,
@@ -372,7 +372,7 @@ static av_always_inline int 
get_dst_color_err(PaletteUseContext *s,
   uint32_t c, int *er, int *eg, 
int *eb,
   const enum color_search_method 
search_method)
 {
-const uint8_t a = c >> 24 & 0xff;
+const uint8_t a = c >> 24;
 const uint8_t r = c >> 16 & 0xff;
 const uint8_t g = c >>  8 & 0xff;
 const uint8_t b = c   & 0xff;
@@ -411,7 +411,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, 
AVFrame *out, AVFram
 
 if (dither == DITHERING_BAYER) {
 const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)];
-const uint8_t a8 = src[x] >> 24 & 0xff;
+const uint8_t a8 = src[x] >> 24;
 const uint8_t r8 = src[x] >> 16 & 0xff;
 const uint8_t g8 = src[x] >>  8 & 0xff;
 const uint8_t b8 = src[x]   & 0xff;
@@ -483,7 +483,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, 
AVFrame *out, AVFram
 if ( down) src[src_linesize + x] = 
dither_color(src[src_linesize + x], er, eg, eb, 1, 2);
 
 } else {
-const uint8_t a = src[x] >> 24 & 0xff;
+const uint8_t a = src[x] >> 24;
 const uint8_t r = src[x] >> 16 & 0xff;
 const uint8_t g = src[x] >>  8 & 0xff;
 const uint8_t b = src[x]   & 0xff;
@@ -630,7 +630,7 @@ static int get_next_color(const uint8_t *color_used, const 
uint32_t *palette,
 
 for (i = 0; i < AVPALETTE_COUNT; i++) {
 const uint32_t c = palette[i];
-const uint8_t a = c >> 24 & 0xff;
+const uint8_t a = c >> 24;
 const uint8_t r = c >> 16 & 0xff;
 const uint8_t g = c >>  8 & 0xff;
 const uint8_t b = c   & 0xff;
@@ -700,7 +700,7 @@ static int colormap_insert(struct color_node *map,
 node = [cur_id];
 node->split = component;
 node->palette_id = pal_id;
-node->val[0] = c>>24 & 0xff;
+node->val[0] = c>>24;
 node->val[1] = c>>16 & 0xff;
 node->val[2] = c>> 8 & 0xff;
 node->val[3] = c & 0xff;
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH v2 02/32] avfilter/palette{gen, use}: revert support palettes with alpha

2022-12-27 Thread Clément Bœsch
This reverts commit dea673d0d548c864ec85f9260d8900d944ef7a2a.

This change cannot work for several reasons, the most obvious ones are:

- the alpha is being part of the scoring of the color difference, even
  though we can not interpret the alpha as part of the perception of the
  color (we don't even know if it's premultiplied or postmultiplied)
- the colors are averaged with their alpha value which simply cannot
  work

The command proposed in the original thread of the patch actually
produces a completely broken file:

ffmpeg -y -loglevel verbose -i fate-suite/apng/o_sample.png -filter_complex 
"split[split1][split2];[split1]palettegen=max_colors=254:use_alpha=1[pal1];[split2][pal1]paletteuse=use_alpha=1"
 -frames:v 1 out.png

We can see that many color pixels are off, but more importantly some
colors have a random alpha value: https://imgur.com/eFQ2UK7

I don't see any easy fix for this unfortunately, the approach appears to
be flawed by design.
---
 doc/filters.texi|   8 --
 libavfilter/vf_palettegen.c | 127 +++-
 libavfilter/vf_paletteuse.c | 225 +++-
 3 files changed, 138 insertions(+), 222 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 9b866de5ae..f51623d16a 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -18474,9 +18474,6 @@ Compute new histogram for each frame.
 @end table
 
 Default value is @var{full}.
-@item use_alpha
-Create a palette of colors with alpha components.
-Setting this, will automatically disable 'reserve_transparent'.
 @end table
 
 The filter also exports the frame metadata @code{lavfi.color_quant_ratio}
@@ -18555,11 +18552,6 @@ will be treated as completely opaque, and values below 
this threshold will be
 treated as completely transparent.
 
 The option must be an integer value in the range [0,255]. Default is @var{128}.
-
-@item use_alpha
-Apply the palette by taking alpha values into account. Only useful with
-palettes that are containing multiple colors with alpha components.
-Setting this will automatically disable 'alpha_treshold'.
 @end table
 
 @subsection Examples
diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index c03f62b942..bea3292796 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -59,7 +59,7 @@ enum {
 };
 
 #define NBITS 5
-#define HIST_SIZE (1<<(4*NBITS))
+#define HIST_SIZE (1<<(3*NBITS))
 
 typedef struct PaletteGenContext {
 const AVClass *class;
@@ -67,7 +67,6 @@ typedef struct PaletteGenContext {
 int max_colors;
 int reserve_transparent;
 int stats_mode;
-int use_alpha;
 
 AVFrame *prev_frame;// previous frame used for the 
diff stats_mode
 struct hist_node histogram[HIST_SIZE];  // histogram/hashtable of the 
colors
@@ -89,7 +88,6 @@ static const AVOption palettegen_options[] = {
 { "full", "compute full frame histograms", 0, AV_OPT_TYPE_CONST, 
{.i64=STATS_MODE_ALL_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" },
 { "diff", "compute histograms only for the part that differs from 
previous frame", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_DIFF_FRAMES}, INT_MIN, 
INT_MAX, FLAGS, "mode" },
 { "single", "compute new histogram for each frame", 0, 
AV_OPT_TYPE_CONST, {.i64=STATS_MODE_SINGLE_FRAMES}, INT_MIN, INT_MAX, FLAGS, 
"mode" },
-{ "use_alpha", "create a palette including alpha values", 
OFFSET(use_alpha), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
 { NULL }
 };
 
@@ -115,16 +113,15 @@ static int cmp_##name(const void *pa, const void *pb)   \
 {   \
 const struct color_ref * const *a = pa; \
 const struct color_ref * const *b = pb; \
-return   (int)((*a)->color >> (8 * (3 - (pos))) & 0xff)  \
-   - (int)((*b)->color >> (8 * (3 - (pos))) & 0xff); \
+return   (int)((*a)->color >> (8 * (2 - (pos))) & 0xff)  \
+   - (int)((*b)->color >> (8 * (2 - (pos))) & 0xff); \
 }
 
-DECLARE_CMP_FUNC(a, 0)
-DECLARE_CMP_FUNC(r, 1)
-DECLARE_CMP_FUNC(g, 2)
-DECLARE_CMP_FUNC(b, 3)
+DECLARE_CMP_FUNC(r, 0)
+DECLARE_CMP_FUNC(g, 1)
+DECLARE_CMP_FUNC(b, 2)
 
-static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b};
+static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
 
 /**
  * Simple color comparison for sorting the final palette
@@ -146,17 +143,6 @@ static av_always_inline int diff(const uint32_t a, const 
uint32_t b)
 return dr*dr + dg*dg + db*db;
 }
 
-static av_always_inline int diff_alpha(const uint32_t a, const uint32_t b)
-{
-const uint8_t c1[] = {a >> 24 & 0xff, a >> 16 & 0xff, a >> 8 & 0xff, a & 
0xff};
-const uint8_t c2[] = {b >> 24 & 0xff, b >> 16 & 0xff, b >> 8 & 0xff, b & 
0xff};
-const int da = c1[0] - c2[0];
-const int dr = c1[1] - c2[1];
-const int dg = c1[2] - c2[2];
-const int db = c1[3] - c2[3];
-return da*da + dr*dr + dg*dg + db*db;
-}
-
 /**
  * Find the next box to split: pick the one 

[FFmpeg-devel] [PATCH v2 01/32] avfilter/palettegen: allow a minimum of 2 colors

2022-12-27 Thread Clément Bœsch
---
 libavfilter/vf_palettegen.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
index 27f74fd147..c03f62b942 100644
--- a/libavfilter/vf_palettegen.c
+++ b/libavfilter/vf_palettegen.c
@@ -82,7 +82,7 @@ typedef struct PaletteGenContext {
 #define OFFSET(x) offsetof(PaletteGenContext, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 static const AVOption palettegen_options[] = {
-{ "max_colors", "set the maximum number of colors to use in the palette", 
OFFSET(max_colors), AV_OPT_TYPE_INT, {.i64=256}, 4, 256, FLAGS },
+{ "max_colors", "set the maximum number of colors to use in the palette", 
OFFSET(max_colors), AV_OPT_TYPE_INT, {.i64=256}, 2, 256, FLAGS },
 { "reserve_transparent", "reserve a palette entry for transparency", 
OFFSET(reserve_transparent), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
 { "transparency_color", "set a background color for transparency", 
OFFSET(transparency_color), AV_OPT_TYPE_COLOR, {.str="lime"}, 0, 0, FLAGS },
 { "stats_mode", "set statistics mode", OFFSET(stats_mode), 
AV_OPT_TYPE_INT, {.i64=STATS_MODE_ALL_FRAMES}, 0, NB_STATS_MODE-1, FLAGS, 
"mode" },
@@ -586,6 +586,11 @@ static int init(AVFilterContext *ctx)
 if (s->use_alpha && s->reserve_transparent)
 s->reserve_transparent = 0;
 
+if (s->max_colors - s->reserve_transparent < 2) {
+av_log(ctx, AV_LOG_ERROR, "max_colors=2 is only allowed without 
reserving a transparent color slot\n");
+return AVERROR(EINVAL);
+}
+
 return 0;
 }
 
-- 
2.39.0

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] New iteration for the color quantization in palette{gen, use}

2022-12-27 Thread Clément Bœsch
Here is a new version of the palette filters patchset. A lot changed
since last iteration. Here are a few highlights:

- The previous version had a terrible typo in the transfer function,
  this is now fixed
- There is now a warning when the frames are not using sRGB transfer
  function (I'm assuming there is no way to automatically insert a
  convert during filter negotiation yet?)
- All the code is now using integer arithmetic so it should be fully
  deterministic WRT tests. For more info, see
  http://blog.pkh.me/p/38-porting-oklab-colorspace-to-integer-arithmetic.html
- The license of the palette utils is now LGPL to align with FFmpeg; the
  OkLab code from Björn Ottosson as well as mine in integers are
  distributed under public domain and MIT so this should be compatible
- The scoring algorithms in the palette generation (heuristics for
  selecting the box and axis) changed after doing an extensive study for
  which you can find the results here:
  https://github.com/ubitux/research/tree/main/color-quantization#results
- Output is more deterministic/stable due to a change in the color
  sorting
- Overall performance is improved quite significantly from previous
  patchset but overall it's still slower than master (with a rough test
  1.06x slower for palettegen and 1.11x slower for paletteuse, your
  mileage may vary), which is expected given the new model. I think
  that's an acceptable trade-off.
- The patchset includes a lot of cleanups and drop of code, leading to
  an overall net negative: 12 files changed, 856 insertions(+), 878
  deletions(-)

Like before, I generated a bunch of outputs at key points in the
history which you can consult here: http://big.pkh.me/pal/ (will be
removed after patchset is merged)

Also, the branch is accessible on github/ubitux/FFmpeg branch
lavfi-palette for convenience.

And happy xmas (a bit late) for those who celebrate it


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH 3/3] avcodec/flacenc: Don't reload bits_per_raw_sample

2022-12-27 Thread Andreas Rheinhardt
This has the advantage of allowing the compiler to
check bits_per_raw_sample only once on little-endian
hardware.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/flacenc.c | 11 ++-
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index adaaa77b79..cdb823a290 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -1574,23 +1574,24 @@ static int write_frame(FlacEncodeContext *s, AVPacket 
*avpkt)
 static int update_md5_sum(FlacEncodeContext *s, const void *samples)
 {
 const uint8_t *buf = samples;
+int bits_per_raw_sample = s->avctx->bits_per_raw_sample;
 int buf_size = s->frame.blocksize * s->channels *
-   ((s->avctx->bits_per_raw_sample + 7) / 8);
+   ((bits_per_raw_sample + 7) / 8);
 
 if (HAVE_BIGENDIAN ||
-s->avctx->bits_per_raw_sample > 16 && s->avctx->bits_per_raw_sample <= 
24) {
+bits_per_raw_sample > 16 && bits_per_raw_sample <= 24) {
 av_fast_malloc(>md5_buffer, >md5_buffer_size, buf_size);
 if (!s->md5_buffer)
 return AVERROR(ENOMEM);
 buf = s->md5_buffer;
 }
 
-if (s->avctx->bits_per_raw_sample <= 16) {
+if (bits_per_raw_sample <= 16) {
 #if HAVE_BIGENDIAN
 s->bdsp.bswap16_buf((uint16_t *) s->md5_buffer,
 samples, buf_size / 2);
 #endif
-} else if (s->avctx->bits_per_raw_sample <= 24) {
+} else if (bits_per_raw_sample <= 24) {
 int i;
 const int32_t *samples0 = samples;
 uint8_t *tmp= s->md5_buffer;
@@ -1600,7 +1601,7 @@ static int update_md5_sum(FlacEncodeContext *s, const 
void *samples)
 AV_WL24(tmp + 3*i, v);
 }
 } else {
-/* s->avctx->bits_per_raw_sample <= 32 */
+/* bits_per_raw_sample <= 32 */
 #if HAVE_BIGENDIAN
 s->bdsp.bswap_buf((uint32_t *) s->md5_buffer,
   samples, s->frame.blocksize * s->channels);
-- 
2.34.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH 2/3] avcodec/flacenc: Don't copy buffer if avoidable

2022-12-27 Thread Andreas Rheinhardt
It is avoidable for 32-bit FLAC on little endian hardware.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/flacenc.c | 20 
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index bf5d12facb..adaaa77b79 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -1573,22 +1573,22 @@ static int write_frame(FlacEncodeContext *s, AVPacket 
*avpkt)
 
 static int update_md5_sum(FlacEncodeContext *s, const void *samples)
 {
-const uint8_t *buf;
+const uint8_t *buf = samples;
 int buf_size = s->frame.blocksize * s->channels *
((s->avctx->bits_per_raw_sample + 7) / 8);
 
-if (s->avctx->bits_per_raw_sample > 16 || HAVE_BIGENDIAN) {
+if (HAVE_BIGENDIAN ||
+s->avctx->bits_per_raw_sample > 16 && s->avctx->bits_per_raw_sample <= 
24) {
 av_fast_malloc(>md5_buffer, >md5_buffer_size, buf_size);
 if (!s->md5_buffer)
 return AVERROR(ENOMEM);
+buf = s->md5_buffer;
 }
 
 if (s->avctx->bits_per_raw_sample <= 16) {
-buf = (const uint8_t *)samples;
 #if HAVE_BIGENDIAN
 s->bdsp.bswap16_buf((uint16_t *) s->md5_buffer,
 samples, buf_size / 2);
-buf = s->md5_buffer;
 #endif
 } else if (s->avctx->bits_per_raw_sample <= 24) {
 int i;
@@ -1599,16 +1599,12 @@ static int update_md5_sum(FlacEncodeContext *s, const 
void *samples)
 int32_t v = samples0[i] >> 8;
 AV_WL24(tmp + 3*i, v);
 }
-buf = s->md5_buffer;
 } else {
 /* s->avctx->bits_per_raw_sample <= 32 */
-int i;
-const int32_t *samples0 = samples;
-uint8_t *tmp= s->md5_buffer;
-
-for (i = 0; i < s->frame.blocksize * s->channels; i++)
-AV_WL32(tmp + 4*i, samples0[i]);
-buf = s->md5_buffer;
+#if HAVE_BIGENDIAN
+s->bdsp.bswap_buf((uint32_t *) s->md5_buffer,
+  samples, s->frame.blocksize * s->channels);
+#endif
 }
 av_md5_update(s->md5ctx, buf, buf_size);
 
-- 
2.34.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] Would a crypto file be acceptable?

2022-12-27 Thread Mark Gaiser
On Tue, Dec 27, 2022 at 10:40 PM Michael Niedermayer 
wrote:

> On Wed, Dec 21, 2022 at 04:44:59PM +0100, Mark Gaiser wrote:
> > Hi,
> >
> > The ffmpeg crypto protocol handler [1] allows one to play encrypted
> media.
> >
> > The great thing here is that it allows playback of any media format that
> > ffmpeg supports!
> > Have a container format like mkv as an encrypted blob, no problem for the
> > crypto plugin!
> >
> > I'm explicitly mentioning mkv (though there's many more) here because
> that
> > isn't possible in HLS/MPD. While those streaming formats handle
> encryption
> > too, they are very limited in terms of supported codecs and containers.
> >
> > Playback of encrypted data works like this:
> > ffplay encrypted_file -decryption_key $AES_KEY -decryption_iv $AES_IV
> >
> > While this works just fine, it's limited in use because the cryptography
> > details have to be passed on the command line. Applications that might
> well
> > support much of ffmpeg functionality can't easily hook into the crypto
> > functionality. Take KODI for example, it allows playback of many of the
> > formats ffmpeg supports but anything with crypto just isn't possible. In
> > fact, anything that requires custom command line arguments isn't
> possible.
> > [2]
> >
> > My idea is to make a new file format that would be implemented and
> specced
> > within [1]. My proposed format would be:
> >
> > ---
> > CRYPTO-VERSION:1
> > CRYPTO-KEY:URI:.
> > CRYPTO-IV:URI:.
> > encrypted_file
> > ---
> >
> > The URI would be a format type identifier where you can choose between
> URI
> > (to pass a URL to a key blob), BASE64URL (key encoded as base64url) or
> HEX.
> >
> > The above proposed format should be stored in a file with ".crypto" as
> > extension. The crypto plugin [1] would then handle that file. The
> arguments
> > would be filled based on the "properties" in the file. So for example the
> > `decryption_key` argument would be populated with the blob returned from
> > CRYPTO-KEY:URI:. Or with one of the other types.
> >
> > The "encrypted_file" would just be passed through ffmpeg's
> > "ffurl_open_whitelist" like the crypto plugin currently does. Meaning
> that
> > the file could be anything ffmpeg supports.
> >
> > Playing encrypted media would be as simple as:
> > ffplay file.crypto
> >
> > With this mail I'm looking for a confirmation if the above concept would
> be
> > allowed as a patch for ffmpeg? And if not, how can I achieve the same
> > results in a way that would be acceptable? [3]
>
> I understand what you are trying to do but not what the use case for this
> is ?
>
> Encryption has the goal to let one party access data and not another.
> Who are these 2 parties and where does the encrypted media come from?
>
> You mention decentralization, I see nothing related to decentralization
> in this. Or do you suggest that, everytime someone succeeds decrypting a
> file its key would be automatically be published in a decentralized
> public database, so teh next user can safe herself teh troubble from
> finding the key?
>
> If not iam confused why you store keys plainly in files, because this is
> not very secure, so maybe the goal never is to keep the key safe ?
> Or it doesnt matter that someone with physical access in the future would
> also possibly have access to the key. Again you didnt explain the use case
> and who the intended user and adversery is ...
>

How do you privately want to share a video with someone else? Say A (you)
and B (the other)
Currently you probably use one of the following options or something
similar:
- A uploads it you youtube as unlisted and share that link with B
- A adds it to google photos/drive and share that link B
- A adds it to cloud storage and shares that link with B
etc..

The common denominator in all those examples is where and how it's stored.
The data is stored in supposedly private storage.
You trust that storage to be private and trust the link to be between you
and the intended target.tended party.

In this setup your video, that is not intended to be public, is shared.
This works and is the "web2" way of doing things.

Now enter web3.
Storage now is publicly available to everyone in the distributed world of
web3.
I know, or can know, what you host and vice versa.
If I were to follow the above sharing model the video - which you had
intended to be private - is now very publicly available.

That's what I'm trying to fix (and am nearly there)!
How I'm fixing this is as follows (this is a bit outside the scope of the
initial question but its context might help you frame the question
properly):
- A has a public and private key pair. So does B.
- A knows the public key of B and vice versa.
- Both A and B have data which is encrypted on their end with keys
unrelated to their own public and private keys
- (this is the important bit!) Wrapped around their private data is a
"metadata" file where their own private key serves to encrypt/decrypt that
file
- A can now re-encrypt 

[FFmpeg-devel] [PATCH 1/3] avcodec/bswapdsp: Don't presume src to be naturally aligned

2022-12-27 Thread Andreas Rheinhardt
src typically comes from AVPackets and AVPacket.data has
no alignment requirement. This means that the casts to
uint32_t* might be undefined behaviour (they are if the
pointer is no suitably aligned) and that the C versions
of the conversion functions presume too much alignment;
I don't know whether the same is true for the riscv asm.

Fix this by using const void* for src.

Signed-off-by: Andreas Rheinhardt 
---
Would be nice if someone could actually check whether riscv
presumes alignment.

 libavcodec/4xm.c |  2 +-
 libavcodec/ac3dec.c  |  2 +-
 libavcodec/alsdec.c  |  2 +-
 libavcodec/apedec.c  |  2 +-
 libavcodec/asvdec.c  |  2 +-
 libavcodec/asvenc.c  |  2 +-
 libavcodec/bswapdsp.c| 37 ++--
 libavcodec/bswapdsp.h|  4 ++--
 libavcodec/cllc.c|  2 +-
 libavcodec/eamad.c   |  2 +-
 libavcodec/eatqi.c   |  3 +--
 libavcodec/flacenc.c |  2 +-
 libavcodec/fraps.c   |  3 +--
 libavcodec/hevcdec.c |  3 +--
 libavcodec/huffyuvdec.c  |  2 +-
 libavcodec/huffyuvenc.c  |  2 +-
 libavcodec/imc.c |  2 +-
 libavcodec/imm4.c|  3 +--
 libavcodec/mdec.c|  2 +-
 libavcodec/mimic.c   |  2 +-
 libavcodec/mobiclip.c|  3 +--
 libavcodec/motionpixels.c|  3 +--
 libavcodec/rawdec.c  |  4 ++--
 libavcodec/riscv/bswapdsp_init.c |  6 +++---
 libavcodec/shorten.c |  2 +-
 libavcodec/truemotion2.c |  3 +--
 libavcodec/truespeech.c  |  2 +-
 libavcodec/utvideodec.c  |  2 +-
 libavcodec/utvideoenc.c  |  3 +--
 libavcodec/x86/bswapdsp.asm  |  2 +-
 libavcodec/x86/bswapdsp_init.c   |  6 +++---
 libavcodec/ylc.c |  2 +-
 32 files changed, 58 insertions(+), 61 deletions(-)

diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c
index 5636fdef2d..570011 100644
--- a/libavcodec/4xm.c
+++ b/libavcodec/4xm.c
@@ -813,7 +813,7 @@ static int decode_i_frame(FourXContext *f, const uint8_t 
*buf, int length)
   prestream_size);
 if (!f->bitstream_buffer)
 return AVERROR(ENOMEM);
-f->bbdsp.bswap_buf(f->bitstream_buffer, (const uint32_t *) prestream,
+f->bbdsp.bswap_buf(f->bitstream_buffer, prestream,
prestream_size / 4);
 init_get_bits(>pre_gb, f->bitstream_buffer, 8 * prestream_size);
 
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 1f2949dcfd..8c7cd547bf 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -1524,7 +1524,7 @@ static int ac3_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 // seems to be byte-swapped AC-3
 int cnt = FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE) >> 1;
 s->bdsp.bswap16_buf((uint16_t *) s->input_buffer,
-(const uint16_t *) buf, cnt);
+buf, cnt);
 } else
 memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
 
diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c
index 4605b2248f..16d6d18895 100644
--- a/libavcodec/alsdec.c
+++ b/libavcodec/alsdec.c
@@ -1900,7 +1900,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*frame,
 *dest++ = av_bswap16(src[sample]);
 } else {
 ctx->bdsp.bswap_buf((uint32_t *) ctx->crc_buffer,
-(uint32_t *) frame->data[0],
+frame->data[0],
 ctx->cur_frame_length * channels);
 }
 crc_source = ctx->crc_buffer;
diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c
index c08d13d6c2..49f27ab2c1 100644
--- a/libavcodec/apedec.c
+++ b/libavcodec/apedec.c
@@ -1499,7 +1499,7 @@ static int ape_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 av_fast_padded_malloc(>data, >data_size, buf_size);
 if (!s->data)
 return AVERROR(ENOMEM);
-s->bdsp.bswap_buf((uint32_t *) s->data, (const uint32_t *) buf,
+s->bdsp.bswap_buf((uint32_t *) s->data, buf,
   buf_size >> 2);
 memset(s->data + (buf_size & ~3), 0, buf_size & 3);
 s->ptr = s->data;
diff --git a/libavcodec/asvdec.c b/libavcodec/asvdec.c
index 699aab9f8f..f5b5800100 100644
--- a/libavcodec/asvdec.c
+++ b/libavcodec/asvdec.c
@@ -254,7 +254,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
 return AVERROR(ENOMEM);
 
 c->bbdsp.bswap_buf((uint32_t *) a->bitstream_buffer,
-   (const uint32_t *) buf, buf_size / 4);
+   buf, buf_size / 4);
 ret = init_get_bits8(>gb, a->bitstream_buffer, buf_size);
 } else {
 ret = init_get_bits8_le(>gb, buf, buf_size);
diff --git a/libavcodec/asvenc.c 

Re: [FFmpeg-devel] [PATCH] avformat/mxfdec: Check index_duration

2022-12-27 Thread Tomas Härdin
tis 2022-12-27 klockan 22:49 +0100 skrev Michael Niedermayer:
> On Tue, Dec 27, 2022 at 07:05:44PM +0100, Marton Balint wrote:
> > 
> > 
> > On Mon, 26 Dec 2022, Michael Niedermayer wrote:
> > 
> > > On Mon, Dec 26, 2022 at 11:32:48AM +0100, Tomas Härdin wrote:
> > > > lör 2022-12-24 klockan 23:50 +0100 skrev Michael Niedermayer:
> > > > > 
> > > > >  index_table->nb_ptses += s->index_duration;
> > > > > +    // If index_duration is substantially larger than
> > > > > nb_index_entries then this algorithm which
> > > > > +    // allocates index_duration elements is a bad idea.
> > > > > All
> > > > > files i tried have it equal
> > > > > +    if (s->index_duration > 10LL * s->nb_index_entries)
> > > > > +    return AVERROR_PATCHWELCOME;
> > > > 
> > > > I was going to say this can overflow but the 10LL ensures it
> > > > can't. So
> > > > looks OK.
> > > 
> > > will apply
> > 
> > Please don't, as far as I see this disallows the usage of partial
> > index
> > tables, so practically rejecting valid files, which is not OK.

Damn, not sure how I missed that. The use of the magic constant 10
should have tipped me off.

> 
> can you share a file that would break ?

mxfenc will produce files like that. It's actually a major deficiency
with the muxer since it produces excessive amounts of partitions.

/Tomas

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avformat/mxfdec: Check index_duration

2022-12-27 Thread Marton Balint



On Tue, 27 Dec 2022, Michael Niedermayer wrote:


On Tue, Dec 27, 2022 at 07:05:44PM +0100, Marton Balint wrote:



On Mon, 26 Dec 2022, Michael Niedermayer wrote:


On Mon, Dec 26, 2022 at 11:32:48AM +0100, Tomas Härdin wrote:

lör 2022-12-24 klockan 23:50 +0100 skrev Michael Niedermayer:


 index_table->nb_ptses += s->index_duration;
+    // If index_duration is substantially larger than
nb_index_entries then this algorithm which
+    // allocates index_duration elements is a bad idea. All
files i tried have it equal
+    if (s->index_duration > 10LL * s->nb_index_entries)
+    return AVERROR_PATCHWELCOME;


I was going to say this can overflow but the 10LL ensures it can't. So
looks OK.


will apply


Please don't, as far as I see this disallows the usage of partial index
tables, so practically rejecting valid files, which is not OK.


can you share a file that would break ?


I don't have such file. But the MXF specs (SMPTE 377-1-2009) explictly 
defines the concept of partial index tables:


"Where all Index Table segments are contiguous, or there is only one 
segment, but not all Edit Units in the Essence Container are indexed, 
these tables are called Partial Index Tables."


As far as I see here nb_index_entries is corresponding to the number of 
indexed edit units, and the number is allowed to be smaller than the index 
duration, because not all edit units have to be indexed.


Regards,
Marton
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avformat/mxfdec: Check index_duration

2022-12-27 Thread Michael Niedermayer
On Tue, Dec 27, 2022 at 07:05:44PM +0100, Marton Balint wrote:
> 
> 
> On Mon, 26 Dec 2022, Michael Niedermayer wrote:
> 
> > On Mon, Dec 26, 2022 at 11:32:48AM +0100, Tomas Härdin wrote:
> > > lör 2022-12-24 klockan 23:50 +0100 skrev Michael Niedermayer:
> > > > 
> > > >  index_table->nb_ptses += s->index_duration;
> > > > +    // If index_duration is substantially larger than
> > > > nb_index_entries then this algorithm which
> > > > +    // allocates index_duration elements is a bad idea. All
> > > > files i tried have it equal
> > > > +    if (s->index_duration > 10LL * s->nb_index_entries)
> > > > +    return AVERROR_PATCHWELCOME;
> > > 
> > > I was going to say this can overflow but the 10LL ensures it can't. So
> > > looks OK.
> > 
> > will apply
> 
> Please don't, as far as I see this disallows the usage of partial index
> tables, so practically rejecting valid files, which is not OK.

can you share a file that would break ?

thx

[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

If you drop bombs on a foreign country and kill a hundred thousand
innocent people, expect your government to call the consequence
"unprovoked inhuman terrorist attacks" and use it to justify dropping
more bombs and killing more people. The technology changed, the idea is old.


signature.asc
Description: PGP signature
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


[FFmpeg-devel] [PATCH] avformat/segment: Add strftime list prefix formatting

2022-12-27 Thread Steven Viola
In the segment muxer, when `strftime` is enabled, apply formatting
to the `segment_list_entry_prefix` string if it's set.

```
ffmpeg -i in.mkv -codec copy -map 0 -f segment \
-segment_list out.csv -segment_list_entry_prefix %Y/ \
-strftime 1 "/var/www/html/%Y/%Y%m%d%H%M%S.ts"
```

Will produce a CSV with the following:

2022/20221227205722.ts,0.00,8.089222
2022/20221227205730.ts,8.089222,18.065856
2022/20221227205740.ts,18.065856,28.075856
2022/20221227205750.ts,28.075856,38.085856

If strftime is not set, then no formatting will be applied to
segment_list_entry_prefix.

Signed-off-by: Steven Viola 
---
 libavformat/segment.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/libavformat/segment.c b/libavformat/segment.c
index c904e20708..4563bff732 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -190,7 +190,9 @@ static int set_segment_filename(AVFormatContext *s)
 size_t size;
 int ret;
 char buf[1024];
+char prefix_buf[1024];
 char *new_name;
+char *new_prefix = NULL;
 
 if (seg->segment_idx_wrap)
 seg->segment_idx %= seg->segment_idx_wrap;
@@ -199,14 +201,24 @@ static int set_segment_filename(AVFormatContext *s)
 struct tm *tm, tmpbuf;
 time();
 tm = localtime_r(, );
+if (seg->entry_prefix) {
+if (!strftime(prefix_buf, sizeof(prefix_buf), seg->entry_prefix, 
tm)) {
+av_log(oc, AV_LOG_ERROR, "Could not get prefix with 
strftime\n");
+return AVERROR(EINVAL);
+}
+new_prefix = av_strdup(prefix_buf);
+}
 if (!strftime(buf, sizeof(buf), s->url, tm)) {
 av_log(oc, AV_LOG_ERROR, "Could not get segment filename with 
strftime\n");
 return AVERROR(EINVAL);
 }
-} else if (av_get_frame_filename(buf, sizeof(buf),
- s->url, seg->segment_idx) < 0) {
-av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", 
s->url);
-return AVERROR(EINVAL);
+} else {
+if (av_get_frame_filename(buf, sizeof(buf),
+  s->url, seg->segment_idx) < 0) {
+av_log(oc, AV_LOG_ERROR, "Invalid segment filename template 
'%s'\n", s->url);
+return AVERROR(EINVAL);
+}
+new_prefix = av_strdup(seg->entry_prefix);
 }
 new_name = av_strdup(buf);
 if (!new_name)
@@ -215,13 +227,13 @@ static int set_segment_filename(AVFormatContext *s)
 
 /* copy modified name in list entry */
 size = strlen(av_basename(oc->url)) + 1;
-if (seg->entry_prefix)
-size += strlen(seg->entry_prefix);
+if (new_prefix)
+size += strlen(new_prefix);
 
 if ((ret = av_reallocp(>cur_entry.filename, size)) < 0)
 return ret;
 snprintf(seg->cur_entry.filename, size, "%s%s",
- seg->entry_prefix ? seg->entry_prefix : "",
+ new_prefix ? new_prefix : "",
  av_basename(oc->url));
 
 return 0;
-- 
2.31.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] Would a crypto file be acceptable?

2022-12-27 Thread Michael Niedermayer
On Wed, Dec 21, 2022 at 04:44:59PM +0100, Mark Gaiser wrote:
> Hi,
> 
> The ffmpeg crypto protocol handler [1] allows one to play encrypted media.
> 
> The great thing here is that it allows playback of any media format that
> ffmpeg supports!
> Have a container format like mkv as an encrypted blob, no problem for the
> crypto plugin!
> 
> I'm explicitly mentioning mkv (though there's many more) here because that
> isn't possible in HLS/MPD. While those streaming formats handle encryption
> too, they are very limited in terms of supported codecs and containers.
> 
> Playback of encrypted data works like this:
> ffplay encrypted_file -decryption_key $AES_KEY -decryption_iv $AES_IV
> 
> While this works just fine, it's limited in use because the cryptography
> details have to be passed on the command line. Applications that might well
> support much of ffmpeg functionality can't easily hook into the crypto
> functionality. Take KODI for example, it allows playback of many of the
> formats ffmpeg supports but anything with crypto just isn't possible. In
> fact, anything that requires custom command line arguments isn't possible.
> [2]
> 
> My idea is to make a new file format that would be implemented and specced
> within [1]. My proposed format would be:
> 
> ---
> CRYPTO-VERSION:1
> CRYPTO-KEY:URI:.
> CRYPTO-IV:URI:.
> encrypted_file
> ---
> 
> The URI would be a format type identifier where you can choose between URI
> (to pass a URL to a key blob), BASE64URL (key encoded as base64url) or HEX.
> 
> The above proposed format should be stored in a file with ".crypto" as
> extension. The crypto plugin [1] would then handle that file. The arguments
> would be filled based on the "properties" in the file. So for example the
> `decryption_key` argument would be populated with the blob returned from
> CRYPTO-KEY:URI:. Or with one of the other types.
> 
> The "encrypted_file" would just be passed through ffmpeg's
> "ffurl_open_whitelist" like the crypto plugin currently does. Meaning that
> the file could be anything ffmpeg supports.
> 
> Playing encrypted media would be as simple as:
> ffplay file.crypto
> 
> With this mail I'm looking for a confirmation if the above concept would be
> allowed as a patch for ffmpeg? And if not, how can I achieve the same
> results in a way that would be acceptable? [3]

I understand what you are trying to do but not what the use case for this is ?

Encryption has the goal to let one party access data and not another.
Who are these 2 parties and where does the encrypted media come from?

You mention decentralization, I see nothing related to decentralization
in this. Or do you suggest that, everytime someone succeeds decrypting a
file its key would be automatically be published in a decentralized
public database, so teh next user can safe herself teh troubble from
finding the key?

If not iam confused why you store keys plainly in files, because this is
not very secure, so maybe the goal never is to keep the key safe ?
Or it doesnt matter that someone with physical access in the future would
also possibly have access to the key. Again you didnt explain the use case
and who the intended user and adversery is ...

thx

[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

The real ebay dictionary, page 1
"Used only once"- "Some unspecified defect prevented a second use"
"In good condition" - "Can be repaird by experienced expert"
"As is" - "You wouldnt want it even if you were payed for it, if you knew ..."


signature.asc
Description: PGP signature
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] fftools/ffmpeg_ffplay_ffprobe_cmdutils: add -mask_url to replace the protocol address in the command with the asterisk (*)

2022-12-27 Thread Michael Niedermayer
On Mon, Dec 26, 2022 at 01:07:51PM +, Wujian(Chin) wrote:
> The issue has been modified. Please review again, thank you!
> 
> Signed-off-by: wujian_nanjing 
> ---
>  doc/fftools-common-opts.texi | 11 +++
>  fftools/cmdutils.c   | 77 
> ++--
>  fftools/cmdutils.h   | 25 ++
>  fftools/ffmpeg.c | 10 +++---
>  fftools/ffplay.c |  9 --
>  fftools/ffprobe.c| 10 +++---
>  6 files changed, 128 insertions(+), 14 deletions(-)

ffmpeg -h
segfaults with this patch

==32366== Invalid read of size 8
==32366==at 0x30836B: split_commandline (in ffmpeg/ffmpeg_g)
==32366==by 0x3039CD: ffmpeg_parse_options (in ffmpeg/ffmpeg_g)
==32366==by 0x2ED201: main (in ffmpeg/ffmpeg_g)
==32366==  Address 0x2ced5290 is 0 bytes after a block of size 16 alloc'd
==32366==at 0x4C33E76: memalign (in 
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32366==by 0x4C33F91: posix_memalign (in 
/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32366==by 0x116B322: av_malloc (in ffmpeg/ffmpeg_g)
==32366==by 0x116B4D8: av_mallocz (in ffmpeg/ffmpeg_g)
==32366==by 0x306469: copy_argv (in ffmpeg/ffmpeg_g)
==32366==by 0x306537: handle_arg_param (in ffmpeg/ffmpeg_g)
==32366==by 0x2ED1F5: main (in ffmpeg/ffmpeg_g)
==32366== 

[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Opposition brings concord. Out of discord comes the fairest harmony.
-- Heraclitus


signature.asc
Description: PGP signature
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] Would a crypto file be acceptable?

2022-12-27 Thread Mark Gaiser
On Mon, Dec 26, 2022 at 12:18 PM Tomas Härdin  wrote:

> mån 2022-12-26 klockan 12:00 +0100 skrev Nicolas George:
> > Tomas Härdin (12022-12-26):
> > > That we want to avoid having keys in the command line is not
> > > unreasonable. A -keyfile argument for crypto: might be appropriate.
> >
> > You are confusing two threads, the issue of credentials visible in
> > the
> > command line is for another proposal. This here is about giving
> > options
> > without giving options, which is a recurring topic.
>
> Right. And trying to smuggle in command line options via a file feels
> made for exploitation..
>

Why so skeptical in that negative demotivating tone?

Isn't any media file "sneaking in options"?
M3U is one, though more of a meta file, it itself doesn't actually store
video data.
MKV is one. It can have wildly different content which defines how the file
is decided/presented.
.. and so you have literally every file ffmpeg supports.

What I'm proposing is conceptually no different than m3u.
I'm even adding in a version to, from a parsing point of view, have some
points to require to be in that file and only handle those that are
"spec-definned".
The file isn't magically going to add in more options that ffmpeg would
blindly swallow, that was never the intention!

My intent with this thread was to start a constructive chat about how to
create a "container format" for encrypted data that we could all agree on.
It would allow encrypted file handling for tools that embed ffmpeg.
A feature that sooner or later will be needed if decentralized storage is
going to be a big thing.

I for example would have liked to know if adding in a key in that file
would be acceptable.
Or if that must be like M3U meaning the key comes from a server and is
never stored in that file.

I suppose the question really is:
1. Should I discuss it further here? With the idea to get to a defined file
format to implement that we agree on!
2. Should I just go for it, make it without further feedback, perhaps show
how it works in a video some months from now. Then try to get this accepted
as PR that implements it (no further feedback requested)? That would be too
late imho hence wanting to discuss it _before_ developing it.

I'm all ears!


>
> /Tomas
>
> ___
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
>
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avformat/mxfdec: Check index_duration

2022-12-27 Thread Marton Balint



On Mon, 26 Dec 2022, Michael Niedermayer wrote:


On Mon, Dec 26, 2022 at 11:32:48AM +0100, Tomas Härdin wrote:

lör 2022-12-24 klockan 23:50 +0100 skrev Michael Niedermayer:


 index_table->nb_ptses += s->index_duration;
+    // If index_duration is substantially larger than
nb_index_entries then this algorithm which
+    // allocates index_duration elements is a bad idea. All
files i tried have it equal
+    if (s->index_duration > 10LL * s->nb_index_entries)
+    return AVERROR_PATCHWELCOME;


I was going to say this can overflow but the 10LL ensures it can't. So
looks OK.


will apply


Please don't, as far as I see this disallows the usage of partial index 
tables, so practically rejecting valid files, which is not OK.


Regards,
Marton
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH v2] avformat/segment: add -strftime_mkdir option

2022-12-27 Thread Steven Viola
I have been using this patch and it has been working great. Surprised that
this functionality isn't already in the muxer.

Steven Viola
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avcodec/mjpegbdec: return the amount of bytes consumed when discarding frames

2022-12-27 Thread James Almer

On 12/26/2022 8:33 AM, James Almer wrote:

EAGAIN is not correct in this scenario. FFCodec.cb.decode() callback decoders
always return the amount of bytes consumed from the input packet (if any), and
report if a frame was generated by setting got_frame.

Signed-off-by: James Almer 
---
  libavcodec/mjpegbdec.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavcodec/mjpegbdec.c b/libavcodec/mjpegbdec.c
index a82a95d70a..6d422e7a29 100644
--- a/libavcodec/mjpegbdec.c
+++ b/libavcodec/mjpegbdec.c
@@ -144,7 +144,7 @@ read_header:
  av_frame_move_ref(rframe, s->picture_ptr);
  s->got_picture = 0;
  if (avctx->skip_frame == AVDISCARD_ALL)
-return AVERROR(EAGAIN);
+return buf_size;
  *got_frame = 1;
  
  if (!s->lossless && avctx->debug & FF_DEBUG_QP) {


Applied.
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avcodec/pnm: avoid mirroring PFM images vertically

2022-12-27 Thread James Almer

On 12/27/2022 10:38 AM, Leo Izen wrote:

On 12/14/22 15:13, Leo Izen wrote:

On 11/29/22 06:14, Anton Khirnov wrote:

Quoting Leo Izen (2022-11-16 12:43:06)

PFM (aka Portable FloatMap) encodes its scanlines from bottom-to-top,
not from top-to-bottom, unlike other NetPBM formats. Without this
patch, FFmpeg ignores this exception and decodes/encodes PFM images
mirrored vertically from their proper orientation.

For reference, see the NetPBM tool pfmtopam, which encodes a .pam
from a .pfm, using the correct orientation (and which FFmpeg reads
correctly). Also compare ffplay to magick display, which shows the
correct orientation as well.

See: http://www.pauldebevec.com/Research/HDR/PFM/ and see:
https://netpbm.sourceforge.net/doc/pfm.html for descriptions of this
image format.

Signed-off-by: Leo Izen 
---
  libavcodec/pnmdec.c  | 10 ++
  libavcodec/pnmenc.c  | 18 ++
  tests/ref/lavf/gbrpf32be.pfm |  2 +-
  tests/ref/lavf/gbrpf32le.pfm |  2 +-
  tests/ref/lavf/grayf32be.pfm |  2 +-
  tests/ref/lavf/grayf32le.pfm |  2 +-
  6 files changed, 24 insertions(+), 12 deletions(-)


Looks reasonable, will push soonish.



I got a LGTM, can someone push this? Thanks.

- Leo Izen (thebombzen)


Did this ever get applied?

- Leo Izen (thebombzen)


No, guess he forgot. Just pushed it, sorry for the delay.
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avcodec/pnm: avoid mirroring PFM images vertically

2022-12-27 Thread Leo Izen

On 12/14/22 15:13, Leo Izen wrote:

On 11/29/22 06:14, Anton Khirnov wrote:

Quoting Leo Izen (2022-11-16 12:43:06)

PFM (aka Portable FloatMap) encodes its scanlines from bottom-to-top,
not from top-to-bottom, unlike other NetPBM formats. Without this
patch, FFmpeg ignores this exception and decodes/encodes PFM images
mirrored vertically from their proper orientation.

For reference, see the NetPBM tool pfmtopam, which encodes a .pam
from a .pfm, using the correct orientation (and which FFmpeg reads
correctly). Also compare ffplay to magick display, which shows the
correct orientation as well.

See: http://www.pauldebevec.com/Research/HDR/PFM/ and see:
https://netpbm.sourceforge.net/doc/pfm.html for descriptions of this
image format.

Signed-off-by: Leo Izen 
---
  libavcodec/pnmdec.c  | 10 ++
  libavcodec/pnmenc.c  | 18 ++
  tests/ref/lavf/gbrpf32be.pfm |  2 +-
  tests/ref/lavf/gbrpf32le.pfm |  2 +-
  tests/ref/lavf/grayf32be.pfm |  2 +-
  tests/ref/lavf/grayf32le.pfm |  2 +-
  6 files changed, 24 insertions(+), 12 deletions(-)


Looks reasonable, will push soonish.



I got a LGTM, can someone push this? Thanks.

- Leo Izen (thebombzen)


Did this ever get applied?

- Leo Izen (thebombzen)


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avfilter/vf_cropdetect: add ability to change limit/reset at runtime

2022-12-27 Thread Jeffrey CHAPUIS



You could just call ff_filter_process_command() instead of hardcoding 
supported commands here. It will ignore any option without the 
AV_OPT_FLAG_RUNTIME_PARAM flag.



This is going to generate memleaks, and needlessly reallocate 
unrelated buffers.
You should instead av_realloc all four s->bboxes buffers here, and 
reset s->limit.


I don't have knowledge in c/c++, I based my changes on vf_crop.c, but i 
will look into your suggestions.


___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".


Re: [FFmpeg-devel] [PATCH] avfilter/vf_cropdetect: add ability to change limit/reset at runtime

2022-12-27 Thread Jeffrey CHAPUIS

Resend whithout line wrap.

Signed-off-by: Ashyni 
---
 doc/filters.texi   | 13 +
 libavfilter/vf_cropdetect.c| 42 +--
 tests/ref/fate/filter-metadata-cropdetect  | 60 +++---
 tests/ref/fate/filter-metadata-cropdetect1 | 14 ++---
 tests/ref/fate/filter-metadata-cropdetect2 | 14 ++---
 5 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index ceab0ea0f..bbb778368 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -10552,6 +10552,19 @@ ffmpeg -flags2 +export_mvs -i file.mp4 -vf 
cropdetect=mode=mvedges,metadata=mode
 @end example
 @end itemize
 +@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item limit
+@item reset, reset_count
+
+The command accepts the same syntax of the corresponding option.
+
+If the specified expression is not valid, it is kept at its current
+value.
+@end table
+
 @anchor{cue}
 @section cue
 diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 7e985fb27..fda803651 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -422,26 +422,57 @@ static int filter_frame(AVFilterLink *inlink, AVFrame 
*frame)
 SET_META("lavfi.cropdetect.h",  h);
 SET_META("lavfi.cropdetect.x",  x);
 SET_META("lavfi.cropdetect.y",  y);
+SET_META("lavfi.cropdetect.pts", frame->pts);
+SET_META("lavfi.cropdetect.limit", limit);
+SET_META("lavfi.cropdetect.reset", s->reset_count);
  av_log(ctx, AV_LOG_INFO,
-   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f 
crop=%d:%d:%d:%d\n",
+   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f 
limit:%d crop=%d:%d:%d:%d\n",
s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * 
av_q2d(inlink->time_base),
-   w, h, x, y);
+   limit, w, h, x, y);
 }
  return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 +static int process_command(AVFilterContext *ctx, const char *cmd, const char 
*args,
+   char *res, int res_len, int flags)
+{
+CropDetectContext *s = ctx->priv;
+int ret;
+
+if (!strcmp(cmd, "limit") || !strcmp(cmd, "reset") || !strcmp(cmd, 
"reset_count")) {
+
+int old_limit = s->limit;
+int old_reset_count = s->reset_count;
+
+AVFilterLink *inlink = ctx->inputs[0];
+
+av_opt_set(s, cmd, args, 0);
+
+if ((ret = config_input(inlink)) < 0) {
+s->limit = old_limit;
+s->reset_count = old_reset_count;
+return ret;
+}
+}
+else
+ret = AVERROR(ENOSYS);
+
+return ret;
+}
+
 #define OFFSET(x) offsetof(CropDetectContext, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM | 
AV_OPT_FLAG_RUNTIME_PARAM
  static const AVOption cropdetect_options[] = {
-{ "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, FLAGS },
+{ "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, TFLAGS },
 { "round", "Value by which the width/height should be divisible", 
OFFSET(round),   AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
-{ "reset", "Recalculate the crop area after this many frames",
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
+{ "reset", "Recalculate the crop area after this many frames",
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, TFLAGS },
 { "skip",  "Number of initial frames to skip",
OFFSET(skip),AV_OPT_TYPE_INT, { .i64 = 2 },  0, INT_MAX, FLAGS },
-{ "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, FLAGS },
+{ "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, TFLAGS },
 { "max_outliers", "Threshold count of outliers",  
OFFSET(max_outliers),AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_BLACK}, 0, 
MODE_NB-1, FLAGS, "mode" },
 { "black","detect black pixels surrounding the video", 0, 
AV_OPT_TYPE_CONST, {.i64=MODE_BLACK},INT_MIN, INT_MAX, FLAGS, "mode" },
@@ -481,4 +512,5 @@ const AVFilter ff_vf_cropdetect = {
 FILTER_OUTPUTS(avfilter_vf_cropdetect_outputs),
 FILTER_PIXFMTS_ARRAY(pix_fmts),
 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | 
AVFILTER_FLAG_METADATA_ONLY,
+.process_command = process_command,
 };
diff --git 

Re: [FFmpeg-devel] [PATCH] avfilter/vf_cropdetect: add ability to change limit/reset at runtime

2022-12-27 Thread James Almer

On 12/27/2022 8:46 AM, Jeffrey CHAPUIS wrote:

Hello, first attempt to contribute.

Related to https://trac.ffmpeg.org/ticket/9851.

Tested with ffmpeg and mpv, amazing results.

Signed-off-by: Ashyni 
---
  doc/filters.texi   | 13 +
  libavfilter/vf_cropdetect.c    | 42 +--
  tests/ref/fate/filter-metadata-cropdetect  | 60 +++---
  tests/ref/fate/filter-metadata-cropdetect1 | 14 ++---
  tests/ref/fate/filter-metadata-cropdetect2 | 14 ++---
  5 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index ceab0ea0f..bbb778368 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -10552,6 +10552,19 @@ ffmpeg -flags2 +export_mvs -i file.mp4 -vf 
cropdetect=mode=mvedges,metadata=mode

  @end example
  @end itemize
  +@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item limit
+@item reset, reset_count
+
+The command accepts the same syntax of the corresponding option.
+
+If the specified expression is not valid, it is kept at its current
+value.
+@end table
+
  @anchor{cue}
  @section cue
  diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 7e985fb27..fda803651 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -422,26 +422,57 @@ static int filter_frame(AVFilterLink *inlink, 
AVFrame *frame)

  SET_META("lavfi.cropdetect.h",  h);
  SET_META("lavfi.cropdetect.x",  x);
  SET_META("lavfi.cropdetect.y",  y);
+    SET_META("lavfi.cropdetect.pts", frame->pts);
+    SET_META("lavfi.cropdetect.limit", limit);
+    SET_META("lavfi.cropdetect.reset", s->reset_count);
   av_log(ctx, AV_LOG_INFO,
-   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d 
pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
+   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d 
pts:%"PRId64" t:%f limit:%d crop=%d:%d:%d:%d\n",

     s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
     frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * 
av_q2d(inlink->time_base),

-   w, h, x, y);
+   limit, w, h, x, y);
  }
   return ff_filter_frame(inlink->dst->outputs[0], frame);
  }
  +static int process_command(AVFilterContext *ctx, const char *cmd, 
const char *args,

+   char *res, int res_len, int flags)
+{
+    CropDetectContext *s = ctx->priv;
+    int ret;
+
+    if (!strcmp(cmd, "limit") || !strcmp(cmd, "reset") || !strcmp(cmd, 
"reset_count")) {


You could just call ff_filter_process_command() instead of hardcoding 
supported commands here. It will ignore any option without the 
AV_OPT_FLAG_RUNTIME_PARAM flag.



+
+    int old_limit = s->limit;
+    int old_reset_count = s->reset_count;
+
+    AVFilterLink *inlink = ctx->inputs[0];
+
+    av_opt_set(s, cmd, args, 0);
+
+    if ((ret = config_input(inlink)) < 0) {


This is going to generate memleaks, and needlessly reallocate unrelated 
buffers.
You should instead av_realloc all four s->bboxes buffers here, and reset 
s->limit.



+    s->limit = old_limit;
+    s->reset_count = old_reset_count;
+    return ret;
+    }
+    }
+    else
+    ret = AVERROR(ENOSYS);
+
+    return ret;
+}
+
  #define OFFSET(x) offsetof(CropDetectContext, x)
  #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM | 
AV_OPT_FLAG_RUNTIME_PARAM

   static const AVOption cropdetect_options[] = {
-    { "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, 
FLAGS },
+    { "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, 
TFLAGS },
  { "round", "Value by which the width/height should be divisible", 
OFFSET(round),   AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
-    { "reset", "Recalculate the crop area after this many frames", 
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
+    { "reset", "Recalculate the crop area after this many frames", 
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, TFLAGS },
  { "skip",  "Number of initial frames to skip", 
OFFSET(skip),    AV_OPT_TYPE_INT, { .i64 = 2 },  0, INT_MAX, FLAGS },
-    { "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, 
FLAGS },
+    { "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, 
TFLAGS },
  { "max_outliers", "Threshold count of outliers", 
OFFSET(max_outliers),AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
  { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, 
{.i64=MODE_BLACK}, 0, MODE_NB-1, FLAGS, 

[FFmpeg-devel] [PATCH] avfilter/vf_cropdetect: add ability to change limit/reset at runtime

2022-12-27 Thread Jeffrey CHAPUIS

Hello, first attempt to contribute.

Related to https://trac.ffmpeg.org/ticket/9851.

Tested with ffmpeg and mpv, amazing results.

Signed-off-by: Ashyni 
---
 doc/filters.texi   | 13 +
 libavfilter/vf_cropdetect.c| 42 +--
 tests/ref/fate/filter-metadata-cropdetect  | 60 +++---
 tests/ref/fate/filter-metadata-cropdetect1 | 14 ++---
 tests/ref/fate/filter-metadata-cropdetect2 | 14 ++---
 5 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index ceab0ea0f..bbb778368 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -10552,6 +10552,19 @@ ffmpeg -flags2 +export_mvs -i file.mp4 -vf 
cropdetect=mode=mvedges,metadata=mode

 @end example
 @end itemize
 +@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item limit
+@item reset, reset_count
+
+The command accepts the same syntax of the corresponding option.
+
+If the specified expression is not valid, it is kept at its current
+value.
+@end table
+
 @anchor{cue}
 @section cue
 diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 7e985fb27..fda803651 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -422,26 +422,57 @@ static int filter_frame(AVFilterLink *inlink, 
AVFrame *frame)

 SET_META("lavfi.cropdetect.h",  h);
 SET_META("lavfi.cropdetect.x",  x);
 SET_META("lavfi.cropdetect.y",  y);
+SET_META("lavfi.cropdetect.pts", frame->pts);
+SET_META("lavfi.cropdetect.limit", limit);
+SET_META("lavfi.cropdetect.reset", s->reset_count);
  av_log(ctx, AV_LOG_INFO,
-   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d 
pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
+   "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d 
pts:%"PRId64" t:%f limit:%d crop=%d:%d:%d:%d\n",

s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * 
av_q2d(inlink->time_base),

-   w, h, x, y);
+   limit, w, h, x, y);
 }
  return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 +static int process_command(AVFilterContext *ctx, const char *cmd, 
const char *args,

+   char *res, int res_len, int flags)
+{
+CropDetectContext *s = ctx->priv;
+int ret;
+
+if (!strcmp(cmd, "limit") || !strcmp(cmd, "reset") || !strcmp(cmd, 
"reset_count")) {

+
+int old_limit = s->limit;
+int old_reset_count = s->reset_count;
+
+AVFilterLink *inlink = ctx->inputs[0];
+
+av_opt_set(s, cmd, args, 0);
+
+if ((ret = config_input(inlink)) < 0) {
+s->limit = old_limit;
+s->reset_count = old_reset_count;
+return ret;
+}
+}
+else
+ret = AVERROR(ENOSYS);
+
+return ret;
+}
+
 #define OFFSET(x) offsetof(CropDetectContext, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define TFLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM | 
AV_OPT_FLAG_RUNTIME_PARAM

  static const AVOption cropdetect_options[] = {
-{ "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, 
FLAGS },
+{ "limit", "Threshold below which the pixel is considered black", 
OFFSET(limit),   AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, 
TFLAGS },
 { "round", "Value by which the width/height should be divisible", 
OFFSET(round),   AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
-{ "reset", "Recalculate the crop area after this many frames", 
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
+{ "reset", "Recalculate the crop area after this many frames", 
OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, TFLAGS },
 { "skip",  "Number of initial frames to skip", 
OFFSET(skip),AV_OPT_TYPE_INT, { .i64 = 2 },  0, INT_MAX, FLAGS },
-{ "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, 
FLAGS },
+{ "reset_count", "Recalculate the crop area after this many 
frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 },  0, INT_MAX, 
TFLAGS },
 { "max_outliers", "Threshold count of outliers", 
OFFSET(max_outliers),AV_OPT_TYPE_INT, { .i64 = 0 },  0, INT_MAX, FLAGS },
 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, 
{.i64=MODE_BLACK}, 0, MODE_NB-1, FLAGS, "mode" },
 { "black","detect black pixels surrounding the video", 
0, AV_OPT_TYPE_CONST, {.i64=MODE_BLACK},INT_MIN, INT_MAX, FLAGS, 
"mode" },

@@ -481,4 +512,5 @@ const AVFilter ff_vf_cropdetect = {
 FILTER_OUTPUTS(avfilter_vf_cropdetect_outputs),
 FILTER_PIXFMTS_ARRAY(pix_fmts),
 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | 
AVFILTER_FLAG_METADATA_ONLY,

+

Re: [FFmpeg-devel] [PATCH v1] fate/jpeg2000: add JPEG 2000 tests using ITU/ISO conformance materials

2022-12-27 Thread Tomas Härdin
mån 2022-12-26 klockan 12:22 -0800 skrev p...@sandflow.com:
> From: Pierre-Anthony Lemieux 
> 
> Adds JPEG 2000 decoder tests using materials from the conformance
> suite specified in
> Rec. ITU-T T.803 | ISO/IEC 15444-4. The jpeg2000dec-ds0_ht_01_b11
> test assumes that
> patchset 
> https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=8078 has
> been applied.
> 
> The test materials are available at 
> https://gitlab.com/wg1/htj2k-codestreams

These are a good start and give us something to shoot for as well as
far as conformance is concerned. With good references we can be more
aggresive come time to optimize the HT decoder :)

/Tomas

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".