size_t avc_parse_annexb(BYTE *extra, int extrasize, BYTE *dst) { size_t dstSize = 0; CH264Nalu Nalu; Nalu.SetBuffer(extra, extrasize, 0); while (Nalu.ReadNext()) { const BYTE *data = Nalu.GetDataBuffer(); if (Nalu.GetType() == NALU_TYPE_SPS || Nalu.GetType() == NALU_TYPE_PPS) { size_t len = Nalu.GetDataLength(); AV_WB16(dst+dstSize, (uint16_t)len); dstSize += 2; memcpy(dst+dstSize, Nalu.GetDataBuffer(), Nalu.GetDataLength()); dstSize += Nalu.GetDataLength(); } } return dstSize; }
void CDXVADecoderH264::CopyBitstream(BYTE* pDXVABuffer, BYTE* pBuffer, UINT& nSize) { CH264Nalu Nalu; int nDummy; int nSlices = 0; UINT m_nSize = nSize; int slice_step = 1; int nDxvaNalLength; while (!nSlices && slice_step <= 2) { Nalu.SetBuffer(pBuffer, m_nSize, slice_step == 1 ? m_nNALLength : 0); nSize = 0; while (Nalu.ReadNext()) { switch (Nalu.GetType()) { case NALU_TYPE_SLICE: case NALU_TYPE_IDR: // Skip the NALU if the data length is below 0 if (Nalu.GetDataLength() < 0) { break; } // For AVC1, put startcode 0x000001 pDXVABuffer[0] = pDXVABuffer[1] = 0; pDXVABuffer[2] = 1; // Copy NALU __try { memcpy(pDXVABuffer + 3, Nalu.GetDataBuffer(), Nalu.GetDataLength()); } __except (EXCEPTION_EXECUTE_HANDLER) { break; } // Update slice control buffer nDxvaNalLength = (int)Nalu.GetDataLength() + 3; m_pSliceShort[nSlices].BSNALunitDataLocation = nSize; m_pSliceShort[nSlices].SliceBytesInBuffer = nDxvaNalLength; nSize += nDxvaNalLength; pDXVABuffer += nDxvaNalLength; nSlices++; break; } } slice_step++; } // Complete with zero padding (buffer size should be a multiple of 128) nDummy = 128 - (nSize % 128); memset(pDXVABuffer, 0, nDummy); m_pSliceShort[nSlices - 1].SliceBytesInBuffer += nDummy; nSize += nDummy; }
HRESULT CDXVADecoderH264_DXVA1::CopyBitstream(BYTE* pDXVABuffer, BYTE* pBuffer, UINT& nSize, UINT nDXVASize/* = UINT_MAX*/) { CH264Nalu Nalu; UINT m_nSize = nSize; int nDxvaNalLength; m_nSlices = 0; Nalu.SetBuffer(pBuffer, m_nSize, m_nNALLength); nSize = 0; while (Nalu.ReadNext()) { switch (Nalu.GetType()) { case NALU_TYPE_SLICE: case NALU_TYPE_IDR: // Skip the NALU if the data length is below 0 if ((int)Nalu.GetDataLength() < 0) { break; } // For AVC1, put startcode 0x000001 pDXVABuffer[0] = pDXVABuffer[1] = 0; pDXVABuffer[2] = 1; // Copy NALU memcpy_sse(pDXVABuffer + 3, Nalu.GetDataBuffer(), Nalu.GetDataLength()); // Update slice control buffer nDxvaNalLength = Nalu.GetDataLength() + 3; m_pSliceShort[m_nSlices].BSNALunitDataLocation = nSize; m_pSliceShort[m_nSlices].SliceBytesInBuffer = nDxvaNalLength; nSize += nDxvaNalLength; pDXVABuffer += nDxvaNalLength; m_nSlices++; break; } } // Complete bitstream buffer with zero padding (buffer size should be a multiple of 128) if (nSize % 128) { int nDummy = 128 - (nSize % 128); memset(pDXVABuffer, 0, nDummy); m_pSliceShort[m_nSlices-1].SliceBytesInBuffer += nDummy; nSize += nDummy; } return S_OK; }
HRESULT CH264SequenceParser::ParseNALs(const BYTE *buffer, size_t buflen, int nal_size) { CH264Nalu nalu; nalu.SetBuffer(buffer, buflen, nal_size); while (nalu.ReadNext()) { const BYTE *data = nalu.GetDataBuffer() + 1; const size_t len = nalu.GetDataLength() - 1; if (nalu.GetType() == NALU_TYPE_SPS) { ParseSPS(data, len); break; } } return S_OK; }
void CDXVADecoderH264::CopyBitstream(BYTE* pDXVABuffer, BYTE* pBuffer, UINT& nSize) { CH264Nalu Nalu; int nDummy; int nSlices = 0; int nDxvaNalLength; Nalu.SetBuffer (pBuffer, nSize, m_nNALLength); nSize = 0; { while (Nalu.ReadNext()) { switch (Nalu.GetType()) { case NALU_TYPE_SLICE: case NALU_TYPE_IDR: // For AVC1, put startcode 0x000001 pDXVABuffer[0]=pDXVABuffer[1]=0;pDXVABuffer[2]=1; // Copy NALU memcpy (pDXVABuffer+3, Nalu.GetDataBuffer(), Nalu.GetDataLength()); // Update slice control buffer nDxvaNalLength = Nalu.GetDataLength()+3; m_pSliceShort[nSlices].BSNALunitDataLocation = nSize; m_pSliceShort[nSlices].SliceBytesInBuffer = nDxvaNalLength; nSize += nDxvaNalLength; pDXVABuffer += nDxvaNalLength; nSlices++; break; } } // Complete with zero padding (buffer size should be a multiple of 128) nDummy = 128 - (nSize %128); memset (pDXVABuffer, 0, nDummy); m_pSliceShort[nSlices-1].SliceBytesInBuffer += nDummy; nSize += nDummy; } }
HRESULT CStreamParser::ParseH264AnnexB(Packet *pPacket) { if (!m_pPacketBuffer) { m_pPacketBuffer = InitPacket(pPacket); } m_pPacketBuffer->Append(pPacket); BYTE *start = m_pPacketBuffer->GetData(); BYTE *end = start + m_pPacketBuffer->GetDataSize(); MOVE_TO_H264_START_CODE(start, end); while(start <= end-4) { BYTE *next = start + 1; MOVE_TO_H264_START_CODE(next, end); // End of buffer reached if(next >= end-4) { break; } size_t size = next - start; CH264Nalu Nalu; Nalu.SetBuffer(start, (int)size, 0); Packet *p2 = NULL; while (Nalu.ReadNext()) { Packet *p3 = new Packet(); p3->SetDataSize(Nalu.GetDataLength() + 4); // Write size of the NALU (Big Endian) AV_WB32(p3->GetData(), (uint32_t)Nalu.GetDataLength()); memcpy(p3->GetData() + 4, Nalu.GetDataBuffer(), Nalu.GetDataLength()); if (!p2) { p2 = p3; } else { p2->Append(p3); SAFE_DELETE(p3); } } if (!p2) break; p2->StreamId = m_pPacketBuffer->StreamId; p2->bDiscontinuity = m_pPacketBuffer->bDiscontinuity; m_pPacketBuffer->bDiscontinuity = FALSE; p2->bSyncPoint = m_pPacketBuffer->bSyncPoint; m_pPacketBuffer->bSyncPoint = FALSE; p2->rtStart = m_pPacketBuffer->rtStart; m_pPacketBuffer->rtStart = Packet::INVALID_TIME; p2->rtStop = m_pPacketBuffer->rtStop; m_pPacketBuffer->rtStop = Packet::INVALID_TIME; p2->pmt = m_pPacketBuffer->pmt; m_pPacketBuffer->pmt = NULL; m_queue.Queue(p2); if(pPacket->rtStart != Packet::INVALID_TIME) { m_pPacketBuffer->rtStart = pPacket->rtStart; m_pPacketBuffer->rtStop = pPacket->rtStop; pPacket->rtStart = Packet::INVALID_TIME; } if(pPacket->bDiscontinuity) { m_pPacketBuffer->bDiscontinuity = pPacket->bDiscontinuity; pPacket->bDiscontinuity = FALSE; } if(pPacket->bSyncPoint) { m_pPacketBuffer->bSyncPoint = pPacket->bSyncPoint; pPacket->bSyncPoint = FALSE; } if(m_pPacketBuffer->pmt) { DeleteMediaType(m_pPacketBuffer->pmt); } m_pPacketBuffer->pmt = pPacket->pmt; pPacket->pmt = NULL; start = next; } if(start > m_pPacketBuffer->GetData()) { m_pPacketBuffer->RemoveHead(start - m_pPacketBuffer->GetData()); } SAFE_DELETE(pPacket); do { pPacket = NULL; REFERENCE_TIME rtStart = Packet::INVALID_TIME, rtStop = rtStart = Packet::INVALID_TIME; std::deque<Packet *>::iterator it; for (it = m_queue.GetQueue()->begin(); it != m_queue.GetQueue()->end(); ++it) { // Skip the first if (it == m_queue.GetQueue()->begin()) { continue; } Packet *p = *it; BYTE* pData = p->GetData(); if((pData[4]&0x1f) == 0x09) { m_bHasAccessUnitDelimiters = true; } if ((pData[4]&0x1f) == 0x09 || (!m_bHasAccessUnitDelimiters && p->rtStart != Packet::INVALID_TIME)) { pPacket = p; if (p->rtStart == Packet::INVALID_TIME && rtStart != Packet::INVALID_TIME) { p->rtStart = rtStart; p->rtStop = rtStop; } break; } if (rtStart == Packet::INVALID_TIME) { rtStart = p->rtStart; rtStop = p->rtStop; } } if (pPacket) { Packet *p = m_queue.Get(); Packet *p2 = NULL; while ((p2 = m_queue.Get()) != pPacket) { p->Append(p2); SAFE_DELETE(p2); } // Return m_queue.GetQueue()->push_front(pPacket); Queue(p); } } while (pPacket != NULL); return S_OK; }
STDMETHODIMP CDecMSDKMVC::Decode(const BYTE *buffer, int buflen, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, BOOL bSyncPoint, BOOL bDiscontinuity) { if (!m_mfxSession) return E_UNEXPECTED; HRESULT hr = S_OK; CBitstreamBuffer bsBuffer(&m_buff); mfxStatus sts = MFX_ERR_NONE; mfxBitstream bs = { 0 }; BOOL bFlush = (buffer == nullptr); if (rtStart >= -TIMESTAMP_OFFSET && rtStart != AV_NOPTS_VALUE) bs.TimeStamp = rtStart + TIMESTAMP_OFFSET; else bs.TimeStamp = MFX_TIMESTAMP_UNKNOWN; bs.DecodeTimeStamp = MFX_TIMESTAMP_UNKNOWN; if (!bFlush) { if (m_pAnnexBConverter) { BYTE *pOutBuffer = nullptr; int pOutSize = 0; hr = m_pAnnexBConverter->Convert(&pOutBuffer, &pOutSize, buffer, buflen); if (FAILED(hr)) return hr; bsBuffer.SetBuffer(pOutBuffer, pOutSize, true); } else { bsBuffer.SetBuffer((BYTE *)buffer, buflen, false); } // Check the buffer for SEI NALU, and some unwanted NALUs that need filtering // MSDK's SEI reading functionality is slightly buggy CH264Nalu nalu; nalu.SetBuffer(bsBuffer.GetBuffer(), bsBuffer.GetBufferSize(), 0); BOOL bNeedFilter = FALSE; while (nalu.ReadNext()) { if (nalu.GetType() == NALU_TYPE_SEI) { ParseSEI(nalu.GetDataBuffer() + 1, nalu.GetDataLength() - 1, bs.TimeStamp); } else if (nalu.GetType() == NALU_TYPE_EOSEQ) { bsBuffer.EnsureWriteable(); // This is rather ugly, and relies on the bitstream being AnnexB, so simply overwriting the EOS NAL with zero works. // In the future a more elaborate bitstream filter might be advised memset(bsBuffer.GetBuffer() + nalu.GetNALPos(), 0, 4); } } bs.Data = bsBuffer.GetBuffer(); bs.DataLength = mfxU32(bsBuffer.GetBufferSize()); bs.MaxLength = bs.DataLength; AddFrameToGOP(bs.TimeStamp); } if (!m_bDecodeReady) { sts = MFXVideoDECODE_DecodeHeader(m_mfxSession, &bs, &m_mfxVideoParams); if (sts == MFX_ERR_NOT_ENOUGH_BUFFER) { hr = AllocateMVCExtBuffers(); if (FAILED(hr)) return hr; sts = MFXVideoDECODE_DecodeHeader(m_mfxSession, &bs, &m_mfxVideoParams); } if (sts == MFX_ERR_NONE) { m_mfxVideoParams.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; m_mfxVideoParams.AsyncDepth = ASYNC_DEPTH; sts = MFXVideoDECODE_Init(m_mfxSession, &m_mfxVideoParams); if (sts != MFX_ERR_NONE) { DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Error initializing the MSDK decoder (%d)", sts)); return E_FAIL; } if (m_mfxExtMVCSeq.NumView != 2) { DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Only MVC with two views is supported")); return E_FAIL; } DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Initialized MVC with View Ids %d, %d", m_mfxExtMVCSeq.View[0].ViewId, m_mfxExtMVCSeq.View[1].ViewId)); m_bDecodeReady = TRUE; } } if (!m_bDecodeReady) return S_FALSE; mfxSyncPoint sync = nullptr; // Loop over the decoder to ensure all data is being consumed while (1) { MVCBuffer *pInputBuffer = GetBuffer(); if (pInputBuffer == nullptr) return E_OUTOFMEMORY; mfxFrameSurface1 *outsurf = nullptr; sts = MFXVideoDECODE_DecodeFrameAsync(m_mfxSession, bFlush ? nullptr : &bs, &pInputBuffer->surface, &outsurf, &sync); if (sts == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM) { DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Incompatible video parameters detected, flushing decoder")); bsBuffer.Clear(); bFlush = TRUE; m_bDecodeReady = FALSE; continue; } if (sync) { MVCBuffer * pOutputBuffer = FindBuffer(outsurf); pOutputBuffer->queued = 1; pOutputBuffer->sync = sync; HandleOutput(pOutputBuffer); continue; } if (sts != MFX_ERR_MORE_SURFACE && sts < 0) break; } if (!bs.DataOffset && !sync && !bFlush) { DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Decoder did not consume any data, discarding")); bs.DataOffset = mfxU32(bsBuffer.GetBufferSize()); } bsBuffer.Consume(bs.DataOffset); if (sts != MFX_ERR_MORE_DATA && sts < 0) { DbgLog((LOG_TRACE, 10, L"CDevMSDKMVC::Decode(): Error from Decode call (%d)", sts)); return S_FALSE; } return S_OK; }