问题
I'm developing a Flutter app to show sequentially videos downloaded from internet. I'm using the Chewie component to show the videos.
This is the UI logic to load the Chewie Widget:
class SliderScreen extends StatefulWidget {
static String id = 'SliderScreen';
@override
_SliderScreenState createState() => _SliderScreenState();
}
class _SliderScreenState extends State<SliderScreen> {
SliderViewModel vModel;
@override
void initState() {
super.initState();
}
@override
void dispose() {
if (null != vModel) vModel.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BaseView<SliderViewModel>(
onModelReady: (model) {
model.downloadController = locator<DownloadController>();
model.downloadController.init(callback: model.onFirstFileDownloaded);
vModel = model;
vModel.getSlots(isFirstCall: true);
},
builder: (context, model, child) => null != model.medias && model.medias.length > 0
? FutureBuilder(
future: model.initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
vModel.chewieController.play();
return AspectRatio(
aspectRatio: 16 / 9,
// Use the VideoPlayer widget to display the video.
child: Center(
child: null != vModel.chewieController ? Chewie(controller: vModel.chewieController) : Center(child: CircularProgressIndicator()),
));
} else {
return SizedBox(
height: 300,
child: Center(child: CircularProgressIndicator()),
);
}
})
: SizedBox());
}
}
And the viewModel where is the download and play the medias.
class SliderViewModel extends BaseViewModel {
static String id = 'SliderViewModel';
static int kFiveMinutes = 5 * 60;
Slot currentSlot;
Slot nextSlot;
DownloadController downloadController;
Timer nextSlotTimer;
List<TaskInfo> medias = [];
VideoPlayerController videoController;
ChewieController chewieController;
bool _disposed = false;
var _isPlaying = false;
var _isEndPlaying = false;
var _canPlay = true;
String token;
int currentIndex = 0;
Future<void> initializeVideoPlayerFuture;
void getSlots({bool isFirstCall = false}) async {
//get videos to show.....
}
void addToDownload({Slot slot, bool resetMedias = false}) async {
if (resetMedias) {
medias.clear();
downloadController.clearTasks();
await downloadController.cancelDownload();
}
await downloadController.addMediasToDownload(ads: slot.ads, slotStart: slot.slot.sta);
downloadController.startDownloadMedias();
}
Future<void> _startPlay() async {
print("play ---------> ${medias[currentIndex].path}");
initializeVideoPlayerFuture = null;
Future.delayed(const Duration(milliseconds: 200), () {
_clearPrevious().then((_) {
_initializePlay();
});
});
}
Future<void> _initializePlay() async {
print('***************** preparing ${medias[currentIndex].path}');
videoController = VideoPlayerController.file(File(medias[currentIndex].path));
videoController.addListener(_controllerListener);
chewieController = ChewieController(
videoPlayerController: videoController,
aspectRatio: 16 / 9,
fullScreenByDefault: true,
showControls: true,
autoPlay: true,
// Prepare the video to be played and display the first frame
autoInitialize: true,
looping: false,
// Errors can occur for example when trying to play a video
// from a non-existent URL
errorBuilder: (context, errorMessage) {
return Center(
child: Text(
errorMessage,
style: TextStyle(color: Colors.white),
),
);
},
);
//chewieController.addListener(_controllerListener);
initializeVideoPlayerFuture = videoController.initialize();
setState(ViewState.Idle);
}
Future<bool> _clearPrevious() async {
await videoController?.pause();
videoController?.removeListener(_controllerListener);
await videoController?.dispose();
return true;
}
void onFirstFileDownloaded(TaskInfo task) {
if (null != task) {
print('current slot: ${currentSlot.slot.sta} - task slot: ${task.slotStart} - ${task.name} FINISH!!!');
if (currentSlot.slot.sta == task.slotStart) {
medias.add(task);
if (!_isPlaying) {
if (_canPlay) {
loadNextMedia();
_canPlay = false;
}
}
}
} else
print('all files downloaded!!!');
}
Future<void> _controllerListener() async {
if (videoController == null || _disposed) {
return;
}
if (!videoController.value.initialized) {
return;
}
final position = await videoController.position;
final duration = videoController.value.duration;
final isPlaying = position.inMilliseconds < duration.inMilliseconds;
final isEndPlaying = position.inMilliseconds > 0 && position.inSeconds == duration.inSeconds;
if (_isPlaying != isPlaying || _isEndPlaying != isEndPlaying) {
_isPlaying = isPlaying;
_isEndPlaying = isEndPlaying;
print(" -----> isPlaying=$isPlaying");
if (!_isPlaying) {
//mark media as viewed
print('send viewed ${medias[currentIndex].ad.id}');
apiServices.sendViewed(
token: token,
adId: medias[currentIndex].ad.id.toString(),
userId: await AppSingleton().storage.read(key: kUserId),
slotId: currentSlot.slot.tsi.toString(),
def: medias[currentIndex].ad.def.toString());
final isComplete = medias.length - 1 == currentIndex;
if (isComplete) {
print("played all!!");
if (currentSlot.slot.loop == 0 || currentSlot.slot.loop == 1 && medias[currentIndex].ad.def == 0) medias.removeAt(currentIndex);
currentIndex = 0;
if (currentSlot.slot.loop == 1) loadNextMedia();
setState(ViewState.Idle);
} else {
_canPlay = true;
print('finish play ${medias[currentIndex].name} - slot: ${medias[currentIndex].slotStart}');
if (currentSlot.slot.loop == 0 || (currentSlot.slot.loop == 1 && medias[currentIndex].ad.def == 0))
medias.removeAt(currentIndex);
else
currentIndex++;
if (medias.length > currentIndex)
loadNextMedia();
else
setState(ViewState.Idle);
}
}
}
}
void loadNextMedia() {
_startPlay();
}
@override
void dispose() {
_disposed = true;
videoController.dispose();
chewieController.dispose();
initializeVideoPlayerFuture = null;
super.dispose();
}
}
Works fine at the beginning, but after some videos are displayed, the app thorws the exception.
Playback error.
E/ExoPlayerImplInternal(12983): com.google.android.exoplayer2.ExoPlaybackException: com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, Format(1, null, null, video/avc, null, -1, null, [1280, 720, -1.0], [-1, -1])
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodec(MediaCodecRenderer.java:479)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.reinitializeCodec(MediaCodecRenderer.java:1261)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1111)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:552)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:647)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:529)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
E/ExoPlayerImplInternal(12983): at android.os.Handler.dispatchMessage(Handler.java:102)
E/ExoPlayerImplInternal(12983): at android.os.Looper.loop(Looper.java:193)
E/ExoPlayerImplInternal(12983): at android.os.HandlerThread.run(HandlerThread.java:65)
E/ExoPlayerImplInternal(12983): Caused by: com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, Format(1, null, null, video/avc, null, -1, null, [1280, 720, -1.0], [-1, -1])
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodecWithFallback(MediaCodecRenderer.java:753)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodec(MediaCodecRenderer.java:474)
E/ExoPlayerImplInternal(12983): ... 9 more
E/ExoPlayerImplInternal(12983): Caused by: android.media.MediaCodec$CodecException: Failed to initialize OMX.qcom.video.decoder.avc, error 0xfffffff4
E/ExoPlayerImplInternal(12983): at android.media.MediaCodec.native_setup(Native Method)
E/ExoPlayerImplInternal(12983): at android.media.MediaCodec.<init>(MediaCodec.java:1811)
E/ExoPlayerImplInternal(12983): at android.media.MediaCodec.createByCodecName(MediaCodec.java:1792)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:802)
E/ExoPlayerImplInternal(12983): at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodecWithFallback(MediaCodecRenderer.java:745)
E/ExoPlayerImplInternal(12983): ... 10 more
The videos are played in loop. That means all videos are played at least one time succesful. In iOS has not tested because can't reproduce videos in simulators.
Thanks in advance.
来源:https://stackoverflow.com/questions/60883887/decoder-init-failed-playing-a-list-of-videos-on-flutter-with-chewie