Decode_Status VaapiDecoderH264::decodeNalu(H264NalUnit * nalu) { Decode_Status status; switch (nalu->type) { case H264_NAL_SLICE_IDR: /* fall-through. IDR specifics are handled in initPicture() */ case H264_NAL_SLICE: if (!m_gotSPS || !m_gotPPS) return DECODE_SUCCESS; status = decodeSlice(nalu); break; case H264_NAL_SPS: status = decodeSPS(nalu); break; case H264_NAL_PPS: status = decodePPS(nalu); break; case H264_NAL_SEI: status = decodeSEI(nalu); break; case H264_NAL_SEQ_END: status = decodeSequenceEnd(); break; case H264_NAL_AU_DELIMITER: /* skip all Access Unit NALs */ status = DECODE_SUCCESS; break; case H264_NAL_FILLER_DATA: /* skip all Filler Data NALs */ status = DECODE_SUCCESS; break; default: WARNING("unsupported NAL unit type %d", nalu->type); status = DECODE_PARSER_FAIL; break; } return status; }
int h264_decode_nalu(DecodingContext_t *dc, const int64_t nalu_offset, const int64_t nalu_size) { TRACE_1(H264, BLD_GREEN "h264_decode_nalu()" CLR_RESET); int retcode = FAILURE; // Goto correct data offset //bitstream_goto_offset(dc->bitstr, nalu_offset); buffer_feed_manual(dc->bitstr, nalu_offset, nalu_size); // Check header validity if (nalu_parse_header(dc->bitstr, dc->active_nalu)) { TRACE_1(H264, "decode: " BLD_GREEN "NALU_TYPE %i (at %lli) " CLR_RESET, dc->active_nalu->nal_unit_type, bitstream_get_absolute_byte_offset(dc->bitstr)); // Decode NAL Unit content switch (dc->active_nalu->nal_unit_type) { case NALU_TYPE_SLICE: ////////////////////////////////////// { TRACE_1(H264, "This decoder only support IDR slice decoding!"); } break; case NALU_TYPE_IDR: //////////////////////////////////////// { TRACE_INFO(H264, "> " BLD_GREEN "decodeIDR(%i at %lli)" CLR_RESET, dc->idrCounter, bitstream_get_absolute_byte_offset(dc->bitstr)); nalu_clean_sample(dc->bitstr); dc->IdrPicFlag = true; if (decode_slice(dc)) { retcode = SUCCESS; dc->errorCounter = 0; dc->idrCounter++; dc->frameCounter++; } else dc->errorCounter++; } break; case NALU_TYPE_AUD: //////////////////////////////////////// { nalu_clean_sample(dc->bitstr); aud_t aud; if (decodeAUD(dc->bitstr, &aud)) { retcode = SUCCESS; } else dc->errorCounter++; } break; case NALU_TYPE_SEI: //////////////////////////////////////// { nalu_clean_sample(dc->bitstr); if (dc->active_sei != NULL) free(dc->active_sei); dc->active_sei = (sei_t*)calloc(1, sizeof(sei_t)); if (dc->active_sei) { if (decodeSEI(dc->bitstr, dc->active_sei)) { retcode = SUCCESS; printSEI(NULL); } else dc->errorCounter++; } } break; case NALU_TYPE_SPS: //////////////////////////////////////// { nalu_clean_sample(dc->bitstr); retcode = decodeSPS_legacy(dc); /* sps_t *sps = (sps_t*)calloc(1, sizeof(sps_t)); if (sps) { if (decodeSPS(dc->bitstr, sps)) { dc->sps_array[sps->seq_parameter_set_id] = sps; dc->active_sps = sps->seq_parameter_set_id; dc->profile_idc = sps->profile_idc; dc->ChromaArrayType = sps->ChromaArrayType; // Init some quantization tables computeLevelScale4x4(dc, sps); computeLevelScale8x8(dc, sps); // Macroblocks "table" allocation (on macroblock **mbs_data): dc->PicSizeInMbs = sps->FrameHeightInMbs * sps->PicWidthInMbs; dc->mb_array = (Macroblock_t**)calloc(dc->PicSizeInMbs, sizeof(Macroblock_t*)); //printSPS(sps); retcode = SUCCESS; } else dc->errorCounter++; } */ } break; case NALU_TYPE_PPS: //////////////////////////////////////// { nalu_clean_sample(dc->bitstr); pps_t *pps = (pps_t*)calloc(1, sizeof(pps_t)); if (pps) { if (decodePPS(dc->bitstr, pps, dc->sps_array)) { dc->pps_array[pps->pic_parameter_set_id] = pps; dc->active_pps = pps->pic_parameter_set_id; dc->entropy_coding_mode_flag = pps->entropy_coding_mode_flag, //printPPS(pps, dc->sps_array); retcode = SUCCESS; } else dc->errorCounter++; } } break; default: { TRACE_ERROR(NALU, "Unsupported NAL Unit! (nal_unit_type %i)", dc->active_nalu->nal_unit_type); dc->errorCounter++; } break; } // Reset NAL Unit structure nalu_reset(dc->active_nalu); } else { retcode = FAILURE; dc->errorCounter++; TRACE_WARNING(NALU, "No valid NAL Unit to decode! (errorCounter = %i)", dc->errorCounter); } return retcode; }
/*! * \brief Decode H.264 bitsream. * \param *input_video A pointer to a VideoFile_t structure, containing every informations available about the current video file. * \param *output_directory The directory where to save exported pictures. * \param picture_format The picture file format. * \param picture_quality The quality we want for exported picture [1;100]. * \param picture_number The number of thumbnail(s) we want to extract. * \param picture_extractionmode The method of distribution for thumbnails extraction. * \return 1 if succeed, 0 otherwise. * * This decoder is based on the 'ITU-T H.264' recommendation: * 'Advanced Video Coding for generic audiovisual services' * It also correspond to 'ISO/IEC 14496-10' international standard, part 10: * 'Advanced Video Coding'. * * You can download the H.264 specification for free on the ITU website: * http://www.itu.int/rec/T-REC-H.264 * * The very first step to H.264 bitstream decoding. Initialize DecodingContext, * then start the decoding process, which loop on NAL Units found in the bitstream. * Each NAL Unit is processed following it's content type. */ int h264_decode(VideoFile_t *input_video, const char *output_directory, const int picture_format, const int picture_quality, const int picture_number, const int picture_extractionmode) { TRACE_INFO(H264, BLD_GREEN "h264_decode()\n" CLR_RESET); int retcode = FAILURE; // Init decoding context DecodingContext_t *dc = initDecodingContext(input_video); if (dc == NULL) { TRACE_ERROR(H264, "Unable to allocate DecodingContext_t, exiting decoder\n"); return retcode; } else { // Init some quantization parameters computeNormAdjust(dc); // Init some export parameters //strncpy(dc->output_directory, output_directory, sizeof(output_directory)); dc->output_format = picture_format; dc->picture_quality = picture_quality; dc->picture_number = picture_number; dc->picture_extractionmode = picture_extractionmode; // Start the decoding process dc->decoderRunning = true; } // Loop until end of file while (dc->decoderRunning) { // Load next NAL Unit retcode = buffer_feed_next_sample(dc->bitstr); // Check header validity if (nalu_parse_header(dc->bitstr, dc->active_nalu)) { // Decode NAL Unit content switch (dc->active_nalu->nal_unit_type) { case NALU_TYPE_SLICE: // 1 { TRACE_1(NALU, "This decoder only support IDR slice decoding!\n"); } break; case NALU_TYPE_IDR: // 5 { dc->IdrPicFlag = true; nalu_clean_sample(dc->bitstr); TRACE_INFO(MAIN, "> " BLD_GREEN "decodeIDR(%i)\n" CLR_RESET, dc->idrCounter); if (decode_slice(dc)) { retcode = SUCCESS; dc->errorCounter = 0; dc->idrCounter++; dc->frameCounter++; } else dc->errorCounter++; dc->IdrPicFlag = false; } break; case NALU_TYPE_SEI: // 6 { nalu_clean_sample(dc->bitstr); if (decodeSEI(dc)) { retcode = SUCCESS; printSEI(dc); } else dc->errorCounter++; } break; case NALU_TYPE_SPS: // 7 { nalu_clean_sample(dc->bitstr); if (decodeSPS(dc)) { retcode = SUCCESS; printSPS(dc); } else dc->errorCounter++; } break; case NALU_TYPE_PPS: // 8 { nalu_clean_sample(dc->bitstr); if (decodePPS(dc)) { retcode = SUCCESS; printPPS(dc); } else dc->errorCounter++; } break; default: { dc->errorCounter++; TRACE_ERROR(NALU, "Unsupported NAL Unit! (nal_unit_type %i)\n", dc->active_nalu->nal_unit_type); } break; } // Reset NAL Unit structure nalu_reset(dc->active_nalu); } else { dc->errorCounter++; TRACE_WARNING(NALU, "No valid NAL Unit to decode! (errorCounter = %i)\n", dc->errorCounter); } if (dc->idrCounter == picture_number) { TRACE_INFO(H264, ">> " BLD_YELLOW "Decoding of %i IDR successfull!\n" CLR_RESET, dc->idrCounter); TRACE_INFO(H264, "H.264 decoding ended\n"); retcode = SUCCESS; dc->decoderRunning = false; } if (dc->errorCounter > 64 || retcode == FAILURE) { TRACE_ERROR(H264, "Error inside NAL Unit decoding loop! (errorCounter = %i) (current nal_unit_type = %i)\n", dc->errorCounter, dc->active_nalu->nal_unit_type); TRACE_ERROR(H264, "H.264 decoding aborted\n"); retcode = FAILURE; dc->decoderRunning = false; } } // Destroy decoding context freeDecodingContext(&dc); // Exit decoder return retcode; }
/** \fn runH264 \brief Index H264 stream */ bool TsIndexer::runH264(const char *file,ADM_TS_TRACK *videoTrac) { bool seq_found=false; bool firstSps=true; TSVideo video; indexerData data; dmxPacketInfo tmpInfo; TS_PESpacket SEI_nal(0); bool result=false; bool bAppend=false; beginConsuming=0; listOfUnits.clear(); printf("Starting H264 indexer\n"); if(!videoTrac) return false; if(videoTrac[0].trackType!=ADM_TS_H264) { printf("[Ts Indexer] Only H264 video supported\n"); return false; } video.pid=videoTrac[0].trackPid; memset(&data,0,sizeof(data)); data.picStructure=pictureFrame; string indexName=string(file); indexName=indexName+string(".idx2"); index=qfopen(indexName,(const char*)"wt"); if(!index) { printf("[PsIndex] Cannot create %s\n",indexName.c_str()); return false; } pkt=new tsPacketLinearTracker(videoTrac->trackPid, audioTracks); FP_TYPE append=FP_DONT_APPEND; if(true==ADM_probeSequencedFile(file)) { if(true==GUI_Question("There are several files with sequential file names. Should they be all loaded ?")) bAppend=true; } if(bAppend==true) append=FP_APPEND; writeSystem(file,bAppend); pkt->open(file,append); data.pkt=pkt; fullSize=pkt->getSize(); gui=createProcessing("Indexing",pkt->getSize()); int lastRefIdc=0; bool keepRunning=true; //****************** // 1 search SPS //****************** while(keepRunning) { int startCode=pkt->findStartCode(); if(startCode&0x80) continue; // Marker missing startCode&=0x1f; if(startCode!=NAL_SPS) continue; // Got SPS! uint32_t xA,xR; // Get info pkt->getInfo(&tmpInfo); // Read just enough... { SEI_nal.empty(); uint32_t code=0xffff+0xffff0000; while(((code&0xffffff)!=1) && pkt->stillOk()) { uint8_t r=pkt->readi8(); code=(code<<8)+r; SEI_nal.pushByte(r); } if(!pkt->stillOk()) break;; pkt->seek(tmpInfo.startAt,tmpInfo.offset-5); if (extractSPSInfo(SEI_nal.payload, SEI_nal.payloadSize-4,&spsInfo)) { ADM_info("[TsIndexer] Found video %"PRIu32"x%"PRIu32", fps=%"PRIu32"\n",video.w,video.h,video.fps); ADM_info("[TsIndexer] SPS says %"PRIu32"x%"PRIu32"\n",spsInfo.width,spsInfo.height); seq_found=1; video.w=spsInfo.width; video.h=spsInfo.height; video.fps=spsInfo.fps1000; xA=spsInfo.darNum; xR=spsInfo.darDen; writeVideo(&video,ADM_TS_H264); writeAudio(); qfprintf(index,"[Data]"); // Rewind break; }; } } if(!seq_found) goto the_end; decodingImage=false; //****************** // 2 Index //****************** bool fourBytes; while(keepRunning) { fourBytes=false; int startCode=pkt->findStartCode2(fourBytes); resume: if(!pkt->stillOk()) break; int startCodeLength=4; if(fourBytes==true) startCodeLength++; // 1:0 2:Nal ref idc 5:Nal Type if(startCode&0x80) { printf("[Ts] Nal Marker missing:%x\n",startCode); continue; // Marker missing } int fullStartCode=startCode; int ref=(startCode>>5)&3; startCode&=0x1f; // Ignore nal ref IDR aprintf("[%02x] Nal :0x%x,ref=%d,lastRef=%d at : %d \n",fullStartCode,startCode,ref,lastRefIdc,pkt->getConsumed()-beginConsuming); // Ignore multiple chunk of the same pic if((startCode==NAL_NON_IDR || startCode==NAL_IDR)&&decodingImage ) { aprintf("Still capturing, ignore\n"); continue; } switch(startCode) { case NAL_AU_DELIMITER: { aprintf("AU DELIMITER\n"); decodingImage = false; } break; case NAL_SEI: { // Load the whole NAL SEI_nal.empty(); uint32_t code=0xffff+0xffff0000; while(((0xffffff&code)!=1) && pkt->stillOk()) { uint8_t r=pkt->readi8(); code=(code<<8)+r; SEI_nal.pushByte(r); } if(!pkt->stillOk()) goto resume; aprintf("[SEI] Nal size :%d\n",SEI_nal.payloadSize); if(SEI_nal.payloadSize>=7) decodeSEI(SEI_nal.payloadSize-4, SEI_nal.payload,&(thisUnit.recoveryCount),&(thisUnit.imageStructure)); else printf("[SEI] Too short size+4=%d\n",*(SEI_nal.payload)); startCode=pkt->readi8(); decodingImage=false; pkt->getInfo(&thisUnit.packetInfo); thisUnit.consumedSoFar=pkt->getConsumed(); if(!addUnit(data,unitTypeSei,thisUnit,startCodeLength+SEI_nal.payloadSize+1)) keepRunning=false; fourBytes=true; goto resume; } break; case NAL_SPS: decodingImage=false; pkt->getInfo(&thisUnit.packetInfo); if(firstSps) { pkt->setConsumed(startCodeLength); // reset consume counter firstSps=false; } thisUnit.consumedSoFar=pkt->getConsumed(); if(!addUnit(data,unitTypeSps,thisUnit,startCodeLength)) keepRunning=false; break; case NAL_IDR: case NAL_NON_IDR: { #define NON_IDR_PRE_READ 8 aprintf("Pic start last ref:%d cur ref:%d nb=%d\n",lastRefIdc,ref,data.nbPics); lastRefIdc=ref; uint8_t bufr[NON_IDR_PRE_READ+4]; uint8_t header[NON_IDR_PRE_READ+4]; pkt->read(NON_IDR_PRE_READ,bufr); // unescape... ADM_unescapeH264(NON_IDR_PRE_READ,bufr,header); // getBits bits(NON_IDR_PRE_READ,header); int first_mb_in_slice,slice_type; first_mb_in_slice= bits.getUEG(); slice_type= bits.getUEG31(); if(slice_type>9) { printf("[TsIndexer] Bad slice type\n"); } if(slice_type>4) slice_type-=5; switch(slice_type) { case 0 : thisUnit.imageType=2;break; // P case 1 : thisUnit.imageType=3;break; // B case 2 : thisUnit.imageType=1;break; // I default : thisUnit.imageType=2;break; // SP/SI } if(startCode==NAL_IDR) thisUnit.imageType=4; // IDR aprintf("[>>>>>>>>] Pic Type %"PRIu32" Recovery %"PRIu32"\n",thisUnit.imageType,recoveryCount); if(thisUnit.imageType==1 && !thisUnit.recoveryCount) thisUnit.imageType=4; //I + Recovery=0 = IDR! data.nbPics++; decodingImage=true; pkt->getInfo(&thisUnit.packetInfo); thisUnit.consumedSoFar=pkt->getConsumed(); if(!addUnit(data,unitTypePic,thisUnit,startCodeLength+NON_IDR_PRE_READ)) keepRunning=false; // reset to default thisUnit.imageStructure=pictureFrame; thisUnit.recoveryCount=0xff; pkt->invalidatePtsDts(); } break; default: break; } } // End while result=true; the_end: printf("\n"); qfprintf(index,"\n[End]\n"); qfclose(index); index=NULL; audioTracks=NULL; delete pkt; pkt=NULL; return result; }