int CDVDVideoCodecVDA::Decode(BYTE* pData, int iSize, double dts, double pts) { CCocoaAutoPool pool; // if (pData) { OSStatus status; double sort_time; uint32_t avc_flags = 0; CFDataRef avc_demux; CFDictionaryRef avc_time; if (m_convert_bytestream) { // convert demuxer packet from bytestream (AnnexB) to bitstream ByteIOContext *pb; int demuxer_bytes; uint8_t *demuxer_content; if(m_dllAvFormat->url_open_dyn_buf(&pb) < 0) { return VC_ERROR; } demuxer_bytes = avc_parse_nal_units(m_dllAvFormat, pb, pData, iSize); demuxer_bytes = m_dllAvFormat->url_close_dyn_buf(pb, &demuxer_content); avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes); m_dllAvUtil->av_free(demuxer_content); } else if (m_convert_3byteTo4byteNALSize) { // convert demuxer packet from 3 byte NAL sizes to 4 byte ByteIOContext *pb; if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0) return VC_ERROR; uint32_t nal_size; uint8_t *end = pData + iSize; uint8_t *nal_start = pData; while (nal_start < end) { nal_size = VDA_RB24(nal_start); m_dllAvFormat->put_be32(pb, nal_size); nal_start += 3; m_dllAvFormat->put_buffer(pb, nal_start, nal_size); nal_start += nal_size; } uint8_t *demuxer_content; int demuxer_bytes = m_dllAvFormat->url_close_dyn_buf(pb, &demuxer_content); avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes); m_dllAvUtil->av_free(demuxer_content); } else { avc_demux = CFDataCreate(kCFAllocatorDefault, pData, iSize); } sort_time = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency(); avc_time = CreateDictionaryWithDisplayTime(sort_time - m_sort_time_offset, dts, pts); if (m_DropPictures) avc_flags = kVDADecoderDecodeFlags_DontEmitFrame; status = m_dll->VDADecoderDecode((VDADecoder)m_vda_decoder, avc_flags, avc_demux, avc_time); CFRelease(avc_time); CFRelease(avc_demux); if (status != kVDADecoderNoErr) { CLog::Log(LOGNOTICE, "%s - VDADecoderDecode failed, status(%d)", __FUNCTION__, (int)status); return VC_ERROR; } } // TODO: queue depth is related to the number of reference frames in encoded h.264. // so we need to buffer until we get N ref frames + 1. if (m_queue_depth < 4) { return VC_BUFFER; } return VC_PICTURE | VC_BUFFER; }
int PrivateDecoderVDA::GetFrame(AVStream *stream, AVFrame *picture, int *got_picture_ptr, AVPacket *pkt) { if (!pkt) CocoaAutoReleasePool pool; int result = -1; if (!m_lib || !stream) return result; AVCodecContext *avctx = stream->codec; if (!avctx) return result; if (pkt) { CFDataRef avc_demux; CFDictionaryRef params; if (m_annexb) { // convert demuxer packet from bytestream (AnnexB) to bitstream AVIOContext *pb; int demuxer_bytes; uint8_t *demuxer_content; if(avio_open_dyn_buf(&pb) < 0) { return result; } demuxer_bytes = avc_parse_nal_units(pb, pkt->data, pkt->size); demuxer_bytes = avio_close_dyn_buf(pb, &demuxer_content); avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes); av_free(demuxer_content); } else if (m_convert_3byteTo4byteNALSize) { // convert demuxer packet from 3 byte NAL sizes to 4 byte AVIOContext *pb; if (avio_open_dyn_buf(&pb) < 0) { return result; } uint32_t nal_size; uint8_t *end = pkt->data + pkt->size; uint8_t *nal_start = pkt->data; while (nal_start < end) { nal_size = VDA_RB24(nal_start); avio_wb32(pb, nal_size); nal_start += 3; avio_write(pb, nal_start, nal_size); nal_start += nal_size; } uint8_t *demuxer_content; int demuxer_bytes = avio_close_dyn_buf(pb, &demuxer_content); avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes); av_free(demuxer_content); } else { avc_demux = CFDataCreate(kCFAllocatorDefault, pkt->data, pkt->size); } CFStringRef keys[4] = { CFSTR("FRAME_PTS"), CFSTR("FRAME_INTERLACED"), CFSTR("FRAME_TFF"), CFSTR("FRAME_REPEAT") }; CFNumberRef values[5]; values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &pkt->pts); values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &picture->interlaced_frame); values[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &picture->top_field_first); values[3] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt8Type, &picture->repeat_pict); params = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys, (const void **)&values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); INIT_ST; vda_st = m_lib->decoderDecode((VDADecoder)m_decoder, 0, avc_demux, params); CHECK_ST; if (vda_st == kVDADecoderNoErr) result = pkt->size; CFRelease(avc_demux); CFRelease(params); } if (m_decoded_frames.size() < m_max_ref_frames) return result; *got_picture_ptr = 1; m_frame_lock.lock(); VDAFrame vdaframe = m_decoded_frames.takeLast(); m_frame_lock.unlock(); if (avctx->get_buffer(avctx, picture) < 0) return -1; picture->reordered_opaque = vdaframe.pts; picture->interlaced_frame = vdaframe.interlaced_frame; picture->top_field_first = vdaframe.top_field_first; picture->repeat_pict = vdaframe.repeat_pict; VideoFrame *frame = (VideoFrame*)picture->opaque; PixelFormat in_fmt = PIX_FMT_NONE; PixelFormat out_fmt = PIX_FMT_NONE; if (vdaframe.format == 'BGRA') in_fmt = PIX_FMT_BGRA; else if (vdaframe.format == '2vuy') in_fmt = PIX_FMT_UYVY422; if (frame->codec == FMT_YV12) out_fmt = PIX_FMT_YUV420P; if (out_fmt != PIX_FMT_NONE && in_fmt != PIX_FMT_NONE && frame->buf) { CVPixelBufferLockBaseAddress(vdaframe.buffer, 0); uint8_t* base = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(vdaframe.buffer, 0); AVPicture img_in, img_out; avpicture_fill(&img_out, (uint8_t *)frame->buf, out_fmt, frame->width, frame->height); avpicture_fill(&img_in, base, in_fmt, frame->width, frame->height); myth_sws_img_convert(&img_out, out_fmt, &img_in, in_fmt, frame->width, frame->height); CVPixelBufferUnlockBaseAddress(vdaframe.buffer, 0); } else { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to convert decoded frame."); } CVPixelBufferRelease(vdaframe.buffer); return result; }
const int isom_write_avcc(DllAvUtil *av_util_ctx, DllAvFormat *av_format_ctx, ByteIOContext *pb, const uint8_t *data, int len) { // extradata from bytestream h264, convert to avcC atom data for bitstream if (len > 6) { /* check for h264 start code */ if (VDA_RB32(data) == 0x00000001 || VDA_RB24(data) == 0x000001) { uint8_t *buf=NULL, *end, *start; uint32_t sps_size=0, pps_size=0; uint8_t *sps=0, *pps=0; int ret = avc_parse_nal_units_buf(av_util_ctx, av_format_ctx, data, &buf, &len); if (ret < 0) return ret; start = buf; end = buf + len; /* look for sps and pps */ while (buf < end) { unsigned int size; uint8_t nal_type; size = VDA_RB32(buf); nal_type = buf[4] & 0x1f; if (nal_type == 7) /* SPS */ { sps = buf + 4; sps_size = size; } else if (nal_type == 8) /* PPS */ { pps = buf + 4; pps_size = size; } buf += size + 4; } assert(sps); av_format_ctx->put_byte(pb, 1); /* version */ av_format_ctx->put_byte(pb, sps[1]); /* profile */ av_format_ctx->put_byte(pb, sps[2]); /* profile compat */ av_format_ctx->put_byte(pb, sps[3]); /* level */ av_format_ctx->put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ av_format_ctx->put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ av_format_ctx->put_be16(pb, sps_size); av_format_ctx->put_buffer(pb, sps, sps_size); if (pps) { av_format_ctx->put_byte(pb, 1); /* number of pps */ av_format_ctx->put_be16(pb, pps_size); av_format_ctx->put_buffer(pb, pps, pps_size); } av_util_ctx->av_free(start); } else { av_format_ctx->put_buffer(pb, data, len); } } return 0; }
const int isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) { // extradata from bytestream h264, convert to avcC atom data for bitstream if (len > 6) { /* check for h264 start code */ if (VDA_RB32(data) == 0x00000001 || VDA_RB24(data) == 0x000001) { uint8_t *buf=NULL, *end, *start; uint32_t sps_size=0, pps_size=0; uint8_t *sps=0, *pps=0; int ret = avc_parse_nal_units_buf(data, &buf, &len); if (ret < 0) return ret; start = buf; end = buf + len; /* look for sps and pps */ while (buf < end) { unsigned int size; uint8_t nal_type; size = VDA_RB32(buf); nal_type = buf[4] & 0x1f; if (nal_type == 7) /* SPS */ { sps = buf + 4; sps_size = size; //parse_sps(sps+1, sps_size-1); } else if (nal_type == 8) /* PPS */ { pps = buf + 4; pps_size = size; } buf += size + 4; } if (!sps) { LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid data (sps)"); return -1; } avio_w8(pb, 1); /* version */ avio_w8(pb, sps[1]); /* profile */ avio_w8(pb, sps[2]); /* profile compat */ avio_w8(pb, sps[3]); /* level */ avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ avio_wb16(pb, sps_size); avio_write(pb, sps, sps_size); if (pps) { avio_w8(pb, 1); /* number of pps */ avio_wb16(pb, pps_size); avio_write(pb, pps, pps_size); } av_free(start); } else { avio_write(pb, data, len); } } return 0; }