@@ -194,24 +194,8 @@ public void release(boolean forCancellation) throws MuxerException {
194
194
195
195
isStarted = false ;
196
196
try {
197
- mediaMuxer . stop ( );
197
+ stopMuxer ( mediaMuxer );
198
198
} catch (RuntimeException e ) {
199
- if (SDK_INT < 30 ) {
200
- // Set the muxer state to stopped even if mediaMuxer.stop() failed so that
201
- // mediaMuxer.release() doesn't attempt to stop the muxer and therefore doesn't throw the
202
- // same exception without releasing its resources. This is already implemented in MediaMuxer
203
- // from API level 30.
204
- try {
205
- Field muxerStoppedStateField = MediaMuxer .class .getDeclaredField ("MUXER_STATE_STOPPED" );
206
- muxerStoppedStateField .setAccessible (true );
207
- int muxerStoppedState = castNonNull ((Integer ) muxerStoppedStateField .get (mediaMuxer ));
208
- Field muxerStateField = MediaMuxer .class .getDeclaredField ("mState" );
209
- muxerStateField .setAccessible (true );
210
- muxerStateField .set (mediaMuxer , muxerStoppedState );
211
- } catch (Exception reflectionException ) {
212
- // Do nothing.
213
- }
214
- }
215
199
// It doesn't matter that stopping the muxer throws if the transformation is being cancelled.
216
200
if (!forCancellation ) {
217
201
throw new MuxerException ("Failed to stop the muxer" , e );
@@ -239,4 +223,32 @@ private static int mimeTypeToMuxerOutputFormat(String mimeType) {
239
223
throw new IllegalArgumentException ("Unsupported output MIME type: " + mimeType );
240
224
}
241
225
}
226
+
227
+ // Accesses MediaMuxer state via reflection to ensure that muxer resources can be released even
228
+ // if stopping fails.
229
+ @ SuppressLint ("PrivateApi" )
230
+ private static void stopMuxer (MediaMuxer mediaMuxer ) {
231
+ try {
232
+ mediaMuxer .stop ();
233
+ } catch (RuntimeException e ) {
234
+ if (SDK_INT < 30 ) {
235
+ // Set the muxer state to stopped even if mediaMuxer.stop() failed so that
236
+ // mediaMuxer.release() doesn't attempt to stop the muxer and therefore doesn't throw the
237
+ // same exception without releasing its resources. This is already implemented in MediaMuxer
238
+ // from API level 30. See also b/80338884.
239
+ try {
240
+ Field muxerStoppedStateField = MediaMuxer .class .getDeclaredField ("MUXER_STATE_STOPPED" );
241
+ muxerStoppedStateField .setAccessible (true );
242
+ int muxerStoppedState = castNonNull ((Integer ) muxerStoppedStateField .get (mediaMuxer ));
243
+ Field muxerStateField = MediaMuxer .class .getDeclaredField ("mState" );
244
+ muxerStateField .setAccessible (true );
245
+ muxerStateField .set (mediaMuxer , muxerStoppedState );
246
+ } catch (Exception reflectionException ) {
247
+ // Do nothing.
248
+ }
249
+ }
250
+ // Rethrow the original error.
251
+ throw e ;
252
+ }
253
+ }
242
254
}
0 commit comments