AVFormatContext* pFormatContext = NULL;
const char* cUrl = [url.absoluteString cStringUsingEncoding:kCFStringEncodingUTF8];
if (avformat_open_input(&pFormatContext, cUrl, NULL, NULL) != 0) {
// Не удалось открыть источник
return;
}
if (avformat_find_stream_info(pFormatContext, NULL) < 0) {
// Не удалось получить информацию о стриме
return;
}
int videoStreamIndex = -1;
for(int i = 0; i < pFormatContext->nb_streams; i++) {
if(pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex < 0) {
// Стрим не найден
return;
}
const AVCodec * pCodec = NULL;
// Поиск декодера по идентификатору
pCodec = avcodec_find_decoder(pFormatContext->streams[videoStreamIndex]->codecpar->codec_id);
if (pCodec == NULL) {
// Декодер не найден
return;
}
AVCodecContext *pCodecCtx = NULL;
AVBufferRef * hwDeviceCtx = NULL;
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx, pFormatContext->streams[videoStreamIndex]->codecpar) != 0) {
// Не Удалось заполнить контекст параметрами
return;
}
// Коллбэк получения идентификатора формата (см. ниже)
pCodecCtx->get_format = get_hw_format;
// Включение возможности аппаратного ускорения
if (av_hwdevice_ctx_create(&hwDeviceCtx, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, NULL, NULL, 0) < 0) {
// Не Удалось включить аппаратное ускорение
return;
}
pCodecCtx->hw_device_ctx = hwDeviceCtx;
// Открытие кодека
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
// Не Удалось открыть кодек
return;
}
static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *pix_fmts)
{
return AV_PIX_FMT_VIDEOTOOLBOX;
}
AVFrame * pFrame = NULL;
// Выделяем память под видео фрейм
pFrame = av_frame_alloc();
if (pFrame == NULL) {
// Не удалось выделить память
return;
}
// Выделяем память под пакет с закодированными видеоданными
AVPacket * pPacket = av_packet_alloc();
if (pPacket == NULL) {
// Не удалось выделить память
return;
}
while (av_read_frame(pFormatContext, pPacket) >= 0) {
// Нам нужны пакеты только от стрима, который мы выбрали выше
if (pPacket->stream_index != videoStreamIndex) {
av_packet_unref(pPacket);
continue;
}
// Перенаправляем пакет с закодированным видео в декодер
int ret = avcodec_send_packet(pCodecCtx, pPacket);
if (ret < 0) {
// Не удалось перенаправить пакет
continue;
}
while (ret >= 0) {
// Пытаемся получить декодированное изображение из декодера
ret = avcodec_receive_frame(pCodecCtx, pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
// Стрим завершен
break;
} else if (ret < 0) {
// Не удалось декодировать пакет
return;
}
// Так как мы указали формат пикселя VideoToolbox, смело кастим pFrame->data[3] в CVPixelBufferRef.
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)pFrame->data[3];
// На этом моменте можно отображать CVPixelBufferRef любым удобным для вас способом
[self->_delegate playerDidOutputFrame:pixelBuffer];
}
av_packet_unref(pPacket);
}