0018-ffmpeg-backport-vtenc-patches.patch 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. From 87cd7de678ddb793468bd64cbdd0a73158bcc524 Mon Sep 17 00:00:00 2001
  2. From: Thomas Guillem <thomas@gllm.fr>
  3. Date: Mon, 18 Jun 2018 12:31:13 +0200
  4. Subject: [PATCH 18/24] ffmpeg: backport vtenc patches
  5. ---
  6. ...lboxenc-fix-mutex-cond-leak-in-error.patch | 35 ++++++
  7. ...videotoolboxenc-split-initialization.patch | 112 ++++++++++++++++++
  8. ...oolboxenc-fix-invalid-session-on-iOS.patch | 48 ++++++++
  9. ...lboxenc-fix-undefined-behavior-with-.patch | 105 ++++++++++++++++
  10. contrib/src/ffmpeg/rules.mak | 4 +
  11. 5 files changed, 304 insertions(+)
  12. create mode 100644 contrib/src/ffmpeg/0001-avcodec-videotoolboxenc-fix-mutex-cond-leak-in-error.patch
  13. create mode 100644 contrib/src/ffmpeg/0002-avcodec-videotoolboxenc-split-initialization.patch
  14. create mode 100644 contrib/src/ffmpeg/0003-avcodec-videotoolboxenc-fix-invalid-session-on-iOS.patch
  15. create mode 100644 contrib/src/ffmpeg/0004-avcodec-videotoolboxenc-fix-undefined-behavior-with-.patch
  16. diff --git a/contrib/src/ffmpeg/0001-avcodec-videotoolboxenc-fix-mutex-cond-leak-in-error.patch b/contrib/src/ffmpeg/0001-avcodec-videotoolboxenc-fix-mutex-cond-leak-in-error.patch
  17. new file mode 100644
  18. index 0000000000..679bd70da3
  19. --- /dev/null
  20. +++ b/contrib/src/ffmpeg/0001-avcodec-videotoolboxenc-fix-mutex-cond-leak-in-error.patch
  21. @@ -0,0 +1,35 @@
  22. +From dea72b148a1250808c625dda0077e43d11689845 Mon Sep 17 00:00:00 2001
  23. +From: Thomas Guillem <thomas@gllm.fr>
  24. +Date: Tue, 29 May 2018 18:04:38 +0200
  25. +Subject: [PATCH 1/4] avcodec/videotoolboxenc: fix mutex/cond leak in error
  26. + path
  27. +
  28. +The leak could happen when the vtenc_create_encoder() function failed.
  29. +---
  30. + libavcodec/videotoolboxenc.c | 5 +++--
  31. + 1 file changed, 3 insertions(+), 2 deletions(-)
  32. +
  33. +diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
  34. +index 086beb41fc..aafef20db0 100644
  35. +--- a/libavcodec/videotoolboxenc.c
  36. ++++ b/libavcodec/videotoolboxenc.c
  37. +@@ -2473,13 +2473,14 @@ static av_cold int vtenc_close(AVCodecContext *avctx)
  38. + {
  39. + VTEncContext *vtctx = avctx->priv_data;
  40. +
  41. ++ pthread_cond_destroy(&vtctx->cv_sample_sent);
  42. ++ pthread_mutex_destroy(&vtctx->lock);
  43. ++
  44. + if(!vtctx->session) return 0;
  45. +
  46. + VTCompressionSessionCompleteFrames(vtctx->session,
  47. + kCMTimeIndefinite);
  48. + clear_frame_queue(vtctx);
  49. +- pthread_cond_destroy(&vtctx->cv_sample_sent);
  50. +- pthread_mutex_destroy(&vtctx->lock);
  51. + CFRelease(vtctx->session);
  52. + vtctx->session = NULL;
  53. +
  54. +--
  55. +2.18.0
  56. +
  57. diff --git a/contrib/src/ffmpeg/0002-avcodec-videotoolboxenc-split-initialization.patch b/contrib/src/ffmpeg/0002-avcodec-videotoolboxenc-split-initialization.patch
  58. new file mode 100644
  59. index 0000000000..c64aa7521a
  60. --- /dev/null
  61. +++ b/contrib/src/ffmpeg/0002-avcodec-videotoolboxenc-split-initialization.patch
  62. @@ -0,0 +1,112 @@
  63. +From 0a83285f54c5c042104a4d2a03c40e8f69a09a3c Mon Sep 17 00:00:00 2001
  64. +From: Thomas Guillem <thomas@gllm.fr>
  65. +Date: Mon, 11 Jun 2018 15:43:56 +0200
  66. +Subject: [PATCH 2/4] avcodec/videotoolboxenc: split initialization
  67. +
  68. +Split vtenc_init() into vtenc_init() (VTEncContext initialization) and
  69. +vtenc_configure_encoder() (creates the vt session).
  70. +
  71. +This commit will allow to restart the vt session while encoding.
  72. +---
  73. + libavcodec/videotoolboxenc.c | 48 +++++++++++++++++++++---------------
  74. + 1 file changed, 28 insertions(+), 20 deletions(-)
  75. +
  76. +diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
  77. +index aafef20db0..0b47a0abac 100644
  78. +--- a/libavcodec/videotoolboxenc.c
  79. ++++ b/libavcodec/videotoolboxenc.c
  80. +@@ -1262,19 +1262,16 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
  81. + return 0;
  82. + }
  83. +
  84. +-static av_cold int vtenc_init(AVCodecContext *avctx)
  85. ++static int vtenc_configure_encoder(AVCodecContext *avctx)
  86. + {
  87. + CFMutableDictionaryRef enc_info;
  88. + CFMutableDictionaryRef pixel_buffer_info;
  89. + CMVideoCodecType codec_type;
  90. + VTEncContext *vtctx = avctx->priv_data;
  91. + CFStringRef profile_level;
  92. +- CFBooleanRef has_b_frames_cfbool;
  93. + CFNumberRef gamma_level = NULL;
  94. + int status;
  95. +
  96. +- pthread_once(&once_ctrl, loadVTEncSymbols);
  97. +-
  98. + codec_type = get_cm_codec_type(avctx->codec_id);
  99. + if (!codec_type) {
  100. + av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id);
  101. +@@ -1304,8 +1301,6 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
  102. + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL);
  103. + }
  104. +
  105. +- vtctx->session = NULL;
  106. +-
  107. + enc_info = CFDictionaryCreateMutable(
  108. + kCFAllocatorDefault,
  109. + 20,
  110. +@@ -1335,8 +1330,6 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
  111. + pixel_buffer_info = NULL;
  112. + }
  113. +
  114. +- pthread_mutex_init(&vtctx->lock, NULL);
  115. +- pthread_cond_init(&vtctx->cv_sample_sent, NULL);
  116. + vtctx->dts_delta = vtctx->has_b_frames ? -1 : 0;
  117. +
  118. + get_cv_transfer_function(avctx, &vtctx->transfer_function, &gamma_level);
  119. +@@ -1363,8 +1356,32 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
  120. + pixel_buffer_info,
  121. + &vtctx->session);
  122. +
  123. +- if (status < 0)
  124. +- goto init_cleanup;
  125. ++init_cleanup:
  126. ++ if (gamma_level)
  127. ++ CFRelease(gamma_level);
  128. ++
  129. ++ if (pixel_buffer_info)
  130. ++ CFRelease(pixel_buffer_info);
  131. ++
  132. ++ CFRelease(enc_info);
  133. ++
  134. ++ return status;
  135. ++}
  136. ++
  137. ++static av_cold int vtenc_init(AVCodecContext *avctx)
  138. ++{
  139. ++ VTEncContext *vtctx = avctx->priv_data;
  140. ++ CFBooleanRef has_b_frames_cfbool;
  141. ++ int status;
  142. ++
  143. ++ pthread_once(&once_ctrl, loadVTEncSymbols);
  144. ++
  145. ++ pthread_mutex_init(&vtctx->lock, NULL);
  146. ++ pthread_cond_init(&vtctx->cv_sample_sent, NULL);
  147. ++
  148. ++ vtctx->session = NULL;
  149. ++ status = vtenc_configure_encoder(avctx);
  150. ++ if (status) return status;
  151. +
  152. + status = VTSessionCopyProperty(vtctx->session,
  153. + kVTCompressionPropertyKey_AllowFrameReordering,
  154. +@@ -1378,16 +1395,7 @@ static av_cold int vtenc_init(AVCodecContext *avctx)
  155. + }
  156. + avctx->has_b_frames = vtctx->has_b_frames;
  157. +
  158. +-init_cleanup:
  159. +- if (gamma_level)
  160. +- CFRelease(gamma_level);
  161. +-
  162. +- if (pixel_buffer_info)
  163. +- CFRelease(pixel_buffer_info);
  164. +-
  165. +- CFRelease(enc_info);
  166. +-
  167. +- return status;
  168. ++ return 0;
  169. + }
  170. +
  171. + static void vtenc_get_frame_info(CMSampleBufferRef buffer, bool *is_key_frame)
  172. +--
  173. +2.18.0
  174. +
  175. diff --git a/contrib/src/ffmpeg/0003-avcodec-videotoolboxenc-fix-invalid-session-on-iOS.patch b/contrib/src/ffmpeg/0003-avcodec-videotoolboxenc-fix-invalid-session-on-iOS.patch
  176. new file mode 100644
  177. index 0000000000..9138060be1
  178. --- /dev/null
  179. +++ b/contrib/src/ffmpeg/0003-avcodec-videotoolboxenc-fix-invalid-session-on-iOS.patch
  180. @@ -0,0 +1,48 @@
  181. +From 72812a3931cda0fcb66d740bbb19c330e97ccbd0 Mon Sep 17 00:00:00 2001
  182. +From: Thomas Guillem <thomas@gllm.fr>
  183. +Date: Mon, 11 Jun 2018 16:17:28 +0200
  184. +Subject: [PATCH 3/4] avcodec/videotoolboxenc: fix invalid session on iOS
  185. +
  186. +Cf. comment. Restart the VT session when the APP goes from foreground to
  187. +background and vice versa.
  188. +---
  189. + libavcodec/videotoolboxenc.c | 23 +++++++++++++++++++++--
  190. + 1 file changed, 21 insertions(+), 2 deletions(-)
  191. +
  192. +diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
  193. +index 0b47a0abac..f516ad7d40 100644
  194. +--- a/libavcodec/videotoolboxenc.c
  195. ++++ b/libavcodec/videotoolboxenc.c
  196. +@@ -2175,8 +2175,27 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx,
  197. + #if TARGET_OS_IPHONE
  198. + pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
  199. + if (!pix_buf_pool) {
  200. +- av_log(avctx, AV_LOG_ERROR, "Could not get pixel buffer pool.\n");
  201. +- return AVERROR_EXTERNAL;
  202. ++ /* On iOS, the VT session is invalidated when the APP switches from
  203. ++ * foreground to background and vice versa. Fetch the actual error code
  204. ++ * of the VT session to detect that case and restart the VT session
  205. ++ * accordingly. */
  206. ++ OSStatus vtstatus;
  207. ++
  208. ++ vtstatus = VTCompressionSessionPrepareToEncodeFrames(vtctx->session);
  209. ++ if (vtstatus == kVTInvalidSessionErr) {
  210. ++ CFRelease(vtctx->session);
  211. ++ vtctx->session = NULL;
  212. ++ status = vtenc_configure_encoder(avctx);
  213. ++ if (status == 0)
  214. ++ pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session);
  215. ++ }
  216. ++ if (!pix_buf_pool) {
  217. ++ av_log(avctx, AV_LOG_ERROR, "Could not get pixel buffer pool.\n");
  218. ++ return AVERROR_EXTERNAL;
  219. ++ }
  220. ++ else
  221. ++ av_log(avctx, AV_LOG_WARNING, "VT session restarted because of a "
  222. ++ "kVTInvalidSessionErr error.\n");
  223. + }
  224. +
  225. + status = CVPixelBufferPoolCreatePixelBuffer(NULL,
  226. +--
  227. +2.18.0
  228. +
  229. diff --git a/contrib/src/ffmpeg/0004-avcodec-videotoolboxenc-fix-undefined-behavior-with-.patch b/contrib/src/ffmpeg/0004-avcodec-videotoolboxenc-fix-undefined-behavior-with-.patch
  230. new file mode 100644
  231. index 0000000000..42f4cce1e6
  232. --- /dev/null
  233. +++ b/contrib/src/ffmpeg/0004-avcodec-videotoolboxenc-fix-undefined-behavior-with-.patch
  234. @@ -0,0 +1,105 @@
  235. +From 029cb11cf13275ec8536d889aae4a307eb987b2f Mon Sep 17 00:00:00 2001
  236. +From: Thomas Guillem <thomas@gllm.fr>
  237. +Date: Tue, 3 Jul 2018 16:59:34 +0200
  238. +Subject: [PATCH 4/4] avcodec/videotoolboxenc: fix undefined behavior with
  239. + rc_max_rate=0
  240. +
  241. +On macOS, a zero rc_max_rate cause an error from
  242. +VTSessionSetProperty(kVTCompressionPropertyKey_DataRateLimits).
  243. +
  244. +on iOS (depending on device/version), a zero rc_max_rate cause invalid
  245. +arguments from the vtenc_output_callback after few frames and then a crash
  246. +within the VideoToolbox library.
  247. +---
  248. + libavcodec/videotoolboxenc.c | 72 ++++++++++++++++++------------------
  249. + 1 file changed, 37 insertions(+), 35 deletions(-)
  250. +
  251. +diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c
  252. +index f516ad7d40..c2f827b9c6 100644
  253. +--- a/libavcodec/videotoolboxenc.c
  254. ++++ b/libavcodec/videotoolboxenc.c
  255. +@@ -1019,44 +1019,46 @@ static int vtenc_create_encoder(AVCodecContext *avctx,
  256. +
  257. + if (vtctx->codec_id == AV_CODEC_ID_H264) {
  258. + // kVTCompressionPropertyKey_DataRateLimits is not available for HEVC
  259. +- bytes_per_second_value = max_rate >> 3;
  260. +- bytes_per_second = CFNumberCreate(kCFAllocatorDefault,
  261. +- kCFNumberSInt64Type,
  262. +- &bytes_per_second_value);
  263. +- if (!bytes_per_second) {
  264. +- return AVERROR(ENOMEM);
  265. +- }
  266. +- one_second_value = 1;
  267. +- one_second = CFNumberCreate(kCFAllocatorDefault,
  268. +- kCFNumberSInt64Type,
  269. +- &one_second_value);
  270. +- if (!one_second) {
  271. +- CFRelease(bytes_per_second);
  272. +- return AVERROR(ENOMEM);
  273. +- }
  274. +- nums[0] = (void *)bytes_per_second;
  275. +- nums[1] = (void *)one_second;
  276. +- data_rate_limits = CFArrayCreate(kCFAllocatorDefault,
  277. +- (const void **)nums,
  278. +- 2,
  279. +- &kCFTypeArrayCallBacks);
  280. +-
  281. +- if (!data_rate_limits) {
  282. ++ if (max_rate > 0) {
  283. ++ bytes_per_second_value = max_rate >> 3;
  284. ++ bytes_per_second = CFNumberCreate(kCFAllocatorDefault,
  285. ++ kCFNumberSInt64Type,
  286. ++ &bytes_per_second_value);
  287. ++ if (!bytes_per_second) {
  288. ++ return AVERROR(ENOMEM);
  289. ++ }
  290. ++ one_second_value = 1;
  291. ++ one_second = CFNumberCreate(kCFAllocatorDefault,
  292. ++ kCFNumberSInt64Type,
  293. ++ &one_second_value);
  294. ++ if (!one_second) {
  295. ++ CFRelease(bytes_per_second);
  296. ++ return AVERROR(ENOMEM);
  297. ++ }
  298. ++ nums[0] = (void *)bytes_per_second;
  299. ++ nums[1] = (void *)one_second;
  300. ++ data_rate_limits = CFArrayCreate(kCFAllocatorDefault,
  301. ++ (const void **)nums,
  302. ++ 2,
  303. ++ &kCFTypeArrayCallBacks);
  304. ++
  305. ++ if (!data_rate_limits) {
  306. ++ CFRelease(bytes_per_second);
  307. ++ CFRelease(one_second);
  308. ++ return AVERROR(ENOMEM);
  309. ++ }
  310. ++ status = VTSessionSetProperty(vtctx->session,
  311. ++ kVTCompressionPropertyKey_DataRateLimits,
  312. ++ data_rate_limits);
  313. ++
  314. + CFRelease(bytes_per_second);
  315. + CFRelease(one_second);
  316. +- return AVERROR(ENOMEM);
  317. +- }
  318. +- status = VTSessionSetProperty(vtctx->session,
  319. +- kVTCompressionPropertyKey_DataRateLimits,
  320. +- data_rate_limits);
  321. ++ CFRelease(data_rate_limits);
  322. +
  323. +- CFRelease(bytes_per_second);
  324. +- CFRelease(one_second);
  325. +- CFRelease(data_rate_limits);
  326. +-
  327. +- if (status) {
  328. +- av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status);
  329. +- return AVERROR_EXTERNAL;
  330. ++ if (status) {
  331. ++ av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status);
  332. ++ return AVERROR_EXTERNAL;
  333. ++ }
  334. + }
  335. +
  336. + if (profile_level) {
  337. +--
  338. +2.18.0
  339. +
  340. diff --git a/contrib/src/ffmpeg/rules.mak b/contrib/src/ffmpeg/rules.mak
  341. index 7a3b678370..7c3a87068c 100644
  342. --- a/contrib/src/ffmpeg/rules.mak
  343. +++ b/contrib/src/ffmpeg/rules.mak
  344. @@ -239,6 +239,10 @@ ifdef USE_FFMPEG
  345. $(APPLY) $(SRC)/ffmpeg/armv7_fixup.patch
  346. $(APPLY) $(SRC)/ffmpeg/dxva_vc1_crash.patch
  347. $(APPLY) $(SRC)/ffmpeg/h264_early_SAR.patch
  348. + $(APPLY) $(SRC)/ffmpeg/0001-avcodec-videotoolboxenc-fix-mutex-cond-leak-in-error.patch
  349. + $(APPLY) $(SRC)/ffmpeg/0002-avcodec-videotoolboxenc-split-initialization.patch
  350. + $(APPLY) $(SRC)/ffmpeg/0003-avcodec-videotoolboxenc-fix-invalid-session-on-iOS.patch
  351. + $(APPLY) $(SRC)/ffmpeg/0004-avcodec-videotoolboxenc-fix-undefined-behavior-with-.patch
  352. endif
  353. ifdef USE_LIBAV
  354. $(APPLY) $(SRC)/ffmpeg/libav_gsm.patch
  355. --
  356. 2.19.1