0

У меня еще раз закончились идеи об ошибке и я вернулся в полезное сообщество переполнения стека. Я понимаю, что это очень длинный пост, чтобы пробраться через него, но я считаю, что он может быть полезен другим в сообществе и предоставляет вызов для ветеранов.NullPointerException при потоковой передаче MediaMetadataRetriever [Android]

По существу, я создаю приложение, которое обрабатывает видео кадр за кадром. Первоначально этот процесс выполнялся линейно, но скорость - это серьезная проблема для этого приложения. Естественная мысль заключалась в том, что для обработки кадров могут быть реализованы отдельные потоки. Каждый поток будет просто одной итерацией предыдущего цикла; извлечение кадра из видео, его обработку и размещение полученных данных в правильный индекс массива.

Вопрос заключается в том, что при переходе от цикла к резьбе, A NullPointerException иногда выбрасывается (примерно один раз каждые 200 кадров), при попытке доступа кадра, возвращенный MediaMetadataRetriever.getFrameAtTime()

Вот некоторые разделы кода, которые могут быть полезны:

Выписка из onClickListener, прикрепленная к кнопке, которая запускает обработку. OnClickListener запускает ThreadPoolExecutor, который управляет потоками для обработки кадров.

long videoLength = getVideoLength(videoUri); 
coords = new coordinate[(int)(videoLength/frameIntervalInMicroSeconds)]; 
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors()+1, 
    Runtime.getRuntime().availableProcessors()+1, 
    1, 
    TimeUnit.SECONDS, 
    new LinkedBlockingQueue<Runnable>()); 
for (long a = 0; a < videoLength; a += frameIntervalInMicroSeconds) { 
    new ProcessFrame().executeOnExecutor(executor, (long) a); 

getVideoFrame(), вспомогательный метод, который принимает в Uri для видео, и время в микросекундах, и возвращает кадр видео как Bitmap

private Bitmap getVideoFrame(Uri uri, long timeInUSeconds) { 
    MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 
    retriever.setDataSource(this, uri); 
    Bitmap temp = retriever.getFrameAtTime(timeInUSeconds, MediaMetadataRetriever.OPTION_CLOSEST); 
    retriever.release(); 
    return temp; 
} 

Выдержка из ProcessFrame, поток (как ASyncTask), который выполняется ThreadPoolExecutor. Как упоминалось выше, поток просто получает фрейм, обрабатывает фрейм и помещает его в нужное место в массиве.

protected Void doInBackground(Long... frameTime){ 
    /* Excluded variable declarations */ 

    Bitmap bMap; 
    synchronized (this) { 
     bMap = getVideoFrame(videoUri, frameTime[0]); 
    } 
    try { 
     //This line below is where the NullPointerException is thrown 
     bMap = Bitmap.createScaledBitmap(bMap, bMap.getWidth()/RESIZE_FACTOR, bMap.getHeight()/RESIZE_FACTOR, true); 
    }catch (Exception e){ 
     System.out.println("Caught NullPointerException"); 
     return null; 
    } 

    /* I excluded the frame processing done here */ 

    //add coordinate to the list 
    try { 
     synchronized (this){ 
      coords[(int) (frameTime[0]/frameIntervalInMicroSeconds)] = temp; 
     } 
    }catch (Exception e){ 
     System.out.println("Caught out of bounds coordinate"); 
    } 

    /* excluded clean up */ 
} 

Сообщение об ошибке производится при нулевой кадр доступен:

7043-7856/com.example.tyler.laserphysicsappb E/MediaMetadataRetrieverJNI﹕ getFrameAtTime: videoFrame is a NULL pointer 

Общие комментарии, замечания и вещи, которые я пробовал:

линия, где исключение помечается с комментарий в последнем блоке кода.

Без блока try/catch мой телефон не отображает сообщение об ошибке обычного приложения в этом исключении, оно мигает черным экраном и затем быстро возвращается на главный экран. (Я обнаружил, какая строка была, быстро сняв скриншот логарифма, пока черный экран мигал)

Без блока try/catch другой телефон, который я попробовал, просто игнорирует ошибку и продолжает, но это разрушает результаты.

Добавление синхронизированного блока вокруг bMap = getVideoFrame (videoUri, frameTime [0]), по-видимому, сделало ошибку менее распространенной, но она все еще происходит.

Я пробовал вариант ffmpegMediaMetadataRetriever. Этот пакет не устранил ошибку и замедлил время обработки.

После исключения nullPointerException все последующие потоки, похоже, с большей вероятностью снова выдадут исключение.

Запуск ThreadPoolExecutor с максимум одним потоком не вызывает ошибки.

Даже если я прилагаю все тело doInBackground() в Синхронизировать блоке, ошибка все равно появляется

+0

Попробуйте «синхронизировать» эту строку: 'bMap = Bitmap.createScaledBitmap (bMap, bMap.getWidth()/RESIZE_FACTOR, bMap.getHeight()/RESIZE_FACTOR, true);'. 'Bitmap.createScaledBitmap()' не ваш метод, поэтому вы, вероятно, не знаете, что он делает за кулисами ... Это статический метод, поэтому могут возникнуть проблемы, если 2 потока одновременно вызовут его. – brso05

+0

Я ценю ваш быстрый ответ, но это не решает проблему. Я оставлю все изменения, хотя они, похоже, не ухудшают ситуацию, и это может быть полезно в долгосрочной перспективе. Спасибо. – TyN101

+0

без проблем жаль, что это не исправить вашу проблему ... – brso05

ответ

0

я смог исправить ошибку, но с тусклыми результатами. Единственный способ, с помощью которого я смог остановить появление исключения, - это установить блок синхронизации вокруг вызова функции getFrameAtTime() MediaMetadataRetriever. Ниже приведен новый метод getVideoFrame.

private Bitmap getVideoFrame(Uri uri, long timeInUSeconds) { 
    MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 
    retriever.setDataSource(this, uri); 
    synchronize (this) { 
     Bitmap temp = retriever.getFrameAtTime(timeInUSeconds, MediaMetadataRetriever.OPTION_CLOSEST); 
    } 
    retriever.release(); 
    return temp; 
} 

К сожалению, как это исправляет ошибку, беспокойство скорости не aleviated, как получить кадр все еще занимает значительное количество времени, гораздо больше, чем на самом деле обработки кадров. Тем не менее, pr

 Смежные вопросы

  • Нет связанных вопросов^_^