Merging gst-plugins-ugly
[platform/upstream/gstreamer.git] / ext / x264 / gstencoderbitrateprofilemanager.c
1 /* GStreamer
2  * Copyright (C) 2019 Thibault Saunier <tsaunier@igalia.com>
3  *
4  * gstencoderbitrateprofilemanager.c
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstencoderbitrateprofilemanager.h"
26
27 GST_DEBUG_CATEGORY_STATIC (encoderbitratemanager_debug);
28 #define GST_CAT_DEFAULT encoderbitratemanager_debug
29
30 typedef struct
31 {
32   gchar *name;
33   gsize n_vals;
34   GstEncoderBitrateTargetForPixelsMap *map;
35 } GstEncoderBitrateProfile;
36
37 struct _GstEncoderBitrateProfileManager
38 {
39   GList *profiles;
40   gchar *preset;
41   guint bitrate;
42
43   gboolean setting_preset;
44   gboolean user_bitrate;
45 };
46
47 /* *INDENT-OFF* */
48 /* Copied from https://support.google.com/youtube/answer/1722171?hl=en */
49 static const GstEncoderBitrateTargetForPixelsMap youtube_bitrate_profiles[] = {
50   {
51         .n_pixels = 3840 * 2160,
52         .low_framerate_bitrate = 40000,
53         .high_framerate_bitrate = 60000,
54   },
55   {
56         .n_pixels = 2560 * 1440,
57         .low_framerate_bitrate = 16000,
58         .high_framerate_bitrate = 24000,
59   },
60   {
61         .n_pixels = 1920 * 1080,
62         .low_framerate_bitrate = 8000,
63         .high_framerate_bitrate = 12000,
64   },
65   {
66         .n_pixels = 1080 * 720,
67         .low_framerate_bitrate = 5000,
68         .high_framerate_bitrate = 7500,
69       },
70   {
71         .n_pixels = 640 * 480,
72         .low_framerate_bitrate = 2500,
73         .high_framerate_bitrate = 4000,
74   },
75   {
76         .n_pixels = 0,
77         .low_framerate_bitrate = 2500,
78         .high_framerate_bitrate = 4000,
79   },
80   {
81         .n_pixels = 0,
82         .low_framerate_bitrate = 0,
83         .high_framerate_bitrate = 0,
84   },
85 };
86 /* *INDENT-ON* */
87
88 static void
89 gst_encoder_bitrate_profile_free (GstEncoderBitrateProfile * profile)
90 {
91   g_free (profile->name);
92   g_free (profile->map);
93   g_free (profile);
94 }
95
96 void
97 gst_encoder_bitrate_profile_manager_add_profile (GstEncoderBitrateProfileManager
98     * self, const gchar * profile_name,
99     const GstEncoderBitrateTargetForPixelsMap * map)
100 {
101   guint n_vals;
102   GstEncoderBitrateProfile *profile;
103
104   for (n_vals = 0;
105       map[n_vals].low_framerate_bitrate != 0
106       && map[n_vals].high_framerate_bitrate != 0; n_vals++);
107   n_vals++;
108
109   profile = g_new0 (GstEncoderBitrateProfile, 1);
110   profile->name = g_strdup (profile_name);
111   profile->n_vals = n_vals;
112   profile->map
113       = g_memdup2 (map, sizeof (GstEncoderBitrateTargetForPixelsMap) * n_vals);
114   self->profiles = g_list_prepend (self->profiles, profile);
115 }
116
117 guint
118 gst_encoder_bitrate_profile_manager_get_bitrate (GstEncoderBitrateProfileManager
119     * self, GstVideoInfo * info)
120 {
121   gint i;
122   gboolean high_fps;
123   guint num_pix;
124   GList *tmp;
125
126   GstEncoderBitrateProfile *profile = NULL;
127
128   g_return_val_if_fail (self != NULL, -1);
129
130   if (!info || info->finfo == NULL
131       || info->finfo->format == GST_VIDEO_FORMAT_UNKNOWN) {
132     GST_INFO ("Video info %p not usable, returning current bitrate", info);
133     return self->bitrate;
134   }
135
136   if (!self->preset) {
137     GST_INFO ("No preset used, returning current bitrate");
138     return self->bitrate;
139
140   }
141
142   for (tmp = self->profiles; tmp; tmp = tmp->next) {
143     GstEncoderBitrateProfile *tmpprof = tmp->data;
144     if (!g_strcmp0 (tmpprof->name, self->preset)) {
145       profile = tmpprof;
146       break;
147     }
148   }
149
150   if (!profile) {
151     GST_INFO ("Could not find map for profile: %s", self->preset);
152
153     return self->bitrate;
154   }
155
156   high_fps = GST_VIDEO_INFO_FPS_N (info) / GST_VIDEO_INFO_FPS_D (info) > 30.0;
157   num_pix = GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info);
158   for (i = 0; i < profile->n_vals; i++) {
159     GstEncoderBitrateTargetForPixelsMap *bitrate_values = &profile->map[i];
160
161     if (num_pix < bitrate_values->n_pixels)
162       continue;
163
164     self->bitrate =
165         high_fps ? bitrate_values->
166         high_framerate_bitrate : bitrate_values->low_framerate_bitrate;
167     GST_INFO ("Using %s bitrate! %d", self->preset, self->bitrate);
168     return self->bitrate;
169   }
170
171   return -1;
172 }
173
174 void gst_encoder_bitrate_profile_manager_start_loading_preset
175     (GstEncoderBitrateProfileManager * self)
176 {
177   self->setting_preset = TRUE;
178 }
179
180 void gst_encoder_bitrate_profile_manager_end_loading_preset
181     (GstEncoderBitrateProfileManager * self, const gchar * preset)
182 {
183   self->setting_preset = FALSE;
184   g_free (self->preset);
185   self->preset = g_strdup (preset);
186 }
187
188 void
189 gst_encoder_bitrate_profile_manager_set_bitrate (GstEncoderBitrateProfileManager
190     * self, guint bitrate)
191 {
192   self->bitrate = bitrate;
193   self->user_bitrate = !self->setting_preset;
194 }
195
196 void
197 gst_encoder_bitrate_profile_manager_free (GstEncoderBitrateProfileManager *
198     self)
199 {
200   g_free (self->preset);
201   g_list_free_full (self->profiles,
202       (GDestroyNotify) gst_encoder_bitrate_profile_free);
203   g_free (self);
204 }
205
206 GstEncoderBitrateProfileManager *
207 gst_encoder_bitrate_profile_manager_new (guint default_bitrate)
208 {
209   GstEncoderBitrateProfileManager *self =
210       g_new0 (GstEncoderBitrateProfileManager, 1);
211   static gsize _init = 0;
212
213   if (g_once_init_enter (&_init)) {
214     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "encoderbitratemanager", 0,
215         "Encoder bitrate manager");
216     g_once_init_leave (&_init, 1);
217   }
218
219   self->bitrate = default_bitrate;
220   gst_encoder_bitrate_profile_manager_add_profile (self,
221       "Profile YouTube", youtube_bitrate_profiles);
222
223   return self;
224 }