Функция «Картинка в картинке» (PiP) позволяет смотреть видео в “плавающем” окне поверх других окон — его можно перемещать по экрану ставить в любое удобное место. Это нужно, чтобы пользователи могли следить за тем, что смотрят и при этом взаимодействовать с другими сайтами или приложениями.

Мы уже писали про реализацию PiP на Android с примерами кода. В этой статье сосредоточимся на iOS.

Картинка в картинке — must have современных мультимедиа приложений

Вот, почему:

  1. Обеспечивает мультизадачность. PiP позволяет пользователям одновременно просматривать видео или изображение в небольшом окне, сохраняя при этом доступ к основному контенту или интерфейсу приложения. Это дает возможность пользователям мультизадачить, например, смотреть видео и одновременно проверять электронную почту, отправлять сообщения или просматривать социальные сети.
  2. Улучшает пользовательский опыт. Режим «картинка в картинке» обеспечивает более гибкую и удобную навигацию по приложению. Это значительно улучшает пользовательский опыт, поскольку не требует прерывания воспроизведения контента или полного переключения контекста.
  3. Минимизирует прерывание сеанса. Режим PiP позволяет пользователям продолжать просмотр или отслеживание содержимого даже во время выполнения других задач. Это помогает снизить прерывания и обеспечивает более плавный и непрерывный рабочий процесс. Например, пользователь может смотреть видеоурок или стрим на YouTube, в то время как ищет информацию в Интернете или пишет заметки.

Все эти факторы помогают удерживать пользователей в приложении, увеличивать продолжительность сеанса использования.

Особенности и сложности PiP на iOS

Apple подразумевает два сценария использования PiP в iOS:

  • для воспроизведения видео
  • для видеозвонков

Главная проблема в том, что для сценария использования PiP для видеозвонков до iOS 16 и для iPad, которые не поддерживают Stage Manager, необходимо запрашивать у Apple специальные права на доступ к камере в режиме многозадачности com.apple.developer. avfoundation.multitasking -camera-access
И даже после нескольких месяцев ожидания — как в нашем случае — Apple все еще может не предоставить их.

Поэтому в нашем мобильном видеочате Tunnel Video Calls мы решили не использовать подобный сценарий. Вместо этого использовали подход: видеозвонок и его контент — это тоже воспроизведение видео.

Жизненный цикл PiP в iOS

Режим “картинка в картинке” — это, технически, обмен контента полноэкранного приложения с PiP-контентом другого. Жизненный цикл такого обмена схематично можно представить так:

Этапы перехода в режим “картинка в картинке” в iOS
Этапы перехода в режим “картинка в картинке” в iOS

Что происходит по порядку:

  1. Проигрывается видео в полноэкранном режиме.
  2. Пользователь инициирует событие, которое требует перехода в режим PiP. Например — нажатие на специальную кнопку или же сворачивание приложения.
  3. Запускается анимация перехода видео в PiP — полноэкранный блок видео уменьшается до миниатюры и перемещается в угол экрана.
  4. Процесс перехода заканчивается и приложение меняет свое состояние на background state.

Затем, когда из Pip видео снова нужно вывести в полноэкранный режим, это происходит в таком порядке:

  1. Приложение в background state и отображает PiP.
  2. Происходит событие, которое иницирует переход из PiP в полноэкранный режим и останавливает режим “картинка в картинке” — нажатие на кнопку или разворачивание приложения. Приложение переходит в Foreground.
  3. Запускается анимация перехода видео в полноэкранный режим. Приложение переходит в состояние полноэкранного показа видео.

Как это выглядит:

Этапы выхода из режима “картинка в картинке” в iOS
Этапы выхода из режима “картинка в картинке” в iOS

Как реализовать PiP для воспроизведения видео

Чтобы PiP заработал, нужно создать объект AVPictureInPictureController(playerLayer: AVPlayerLayer). На него обязательно должна быть сильная ссылка.

 
 if AVPictureInPictureController.isPictureInPictureSupported() {
       // Create a new controller, passing the reference to the AVPlayerLayer.
         pipController = AVPictureInPictureController(playerLayer: playerLayer)     	pipController.delegate = self
             pipController.canStartPictureInPictureAutomaticallyFromInline = true}
 

Дальше нужно начать воспроизведение видео контента

 
 func publishNowPlayingMetadata() {
   nowPlayingSession.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
      nowPlayingSession.becomeActiveIfPossible()
}
 

После этого при нажатии на кнопку или сворачивании / разворачивании приложения будет запускаться PiP:

 
 func togglePictureInPictureMode(_ sender: UIButton) {
   if pipController.isPictureInPictureActive {
          pipController.stopPictureInPicture()
   } else {
       pipController.startPictureInPicture()
   }
}
 

Как реализовать PiP для видеозвонка

Рреализация режима “картинка в картинке” в iOS приложении для видеозвонков на технологии WebRTC — пожалуй, самая сложная часть работы. Мы будем рады помочь, напишите нам — обсудим детали. Идейно:

При такой реализации камера не будет захватывать изображение пользователя и можно будет только увидеть собеседника.

Для этого нужно:

  1. Создать объект AVPictureInPictureController
  2. Получить RTCVideoFrame
  3. Получить и заполнить CMSampleBuffer на основе RTCVideoFrame
  4. Передать CMSampleBuffer и отобразить его в AVSampleBufferDisplayLayer

Вот, как это выглядит на диаграмме последовательностей:

Диаграмма последовательности реализации PiP в iOS
Диаграмма последовательности реализации PiP в iOS

  • Разработка