static void enc_postprocess(MSFilter *f) { EncData *d=(EncData*)f->data; rfc3984_destroy(d->packer); AMediaCodec_flush(d->codec); AMediaCodec_stop(d->codec); d->packer=NULL; }
void mylooper::handle(int what, void *obj) { switch (what) { case kMsgCodecBuffer: doCodecWork((workerdata *) obj); break; case kMsgDecodeDone: { workerdata *d = (workerdata *) obj; AMediaCodec_stop(d->codec); AMediaCodec_delete(d->codec); AMediaExtractor_delete(d->ex); d->sawInputEOS = true; d->sawOutputEOS = true; } break; case kMsgSeek: { workerdata *d = (workerdata *) obj; AMediaExtractor_seekTo(d->ex, 0, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC); AMediaCodec_flush(d->codec); d->renderstart = -1; d->sawInputEOS = false; d->sawOutputEOS = false; d->isPlaying = true; post(kMsgCodecBuffer, d); } break; case kMsgPause: { workerdata *d = (workerdata *) obj; if (d->isPlaying) { // flush all outstanding codecbuffer messages with a no-op message d->isPlaying = false; post(kMsgPauseAck, NULL, true); } } break; case kMsgResume: { workerdata *d = (workerdata *) obj; if (!d->isPlaying) { d->renderstart = -1; d->isPlaying = true; post(kMsgCodecBuffer, d); } } break; } }
static void dec_reinit(DecData *d){ AMediaFormat *format; AMediaCodec_flush(d->codec); AMediaCodec_stop(d->codec); AMediaCodec_delete(d->codec); ms_message("Restart dec"); d->codec = AMediaCodec_createDecoderByType("video/avc"); format = AMediaFormat_new(); AMediaFormat_setString(format,"mime","video/avc"); //Size mandatory for decoder configuration AMediaFormat_setInt32(format,"width",1920); AMediaFormat_setInt32(format,"height",1080); AMediaCodec_configure(d->codec, format, NULL, NULL, 0); AMediaCodec_start(d->codec); AMediaFormat_delete(format); }
static void dec_process(MSFilter *f){ DecData *d=(DecData*)f->data; MSPicture pic = {0}; mblk_t *im,*om = NULL; ssize_t oBufidx = -1; size_t bufsize; bool_t need_reinit=FALSE; bool_t request_pli=FALSE; MSQueue nalus; AMediaCodecBufferInfo info; ms_queue_init(&nalus); while((im=ms_queue_get(f->inputs[0]))!=NULL){ if (d->packet_num==0 && d->sps && d->pps){ mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im)); mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im)); rfc3984_unpack(&d->unpacker, d->sps, &nalus); rfc3984_unpack(&d->unpacker, d->pps, &nalus); d->sps=NULL; d->pps=NULL; } if(rfc3984_unpack(&d->unpacker,im,&nalus) <0){ request_pli=TRUE; } if (!ms_queue_empty(&nalus)){ int size; uint8_t *buf=NULL; ssize_t iBufidx; size=nalusToFrame(d,&nalus,&need_reinit); if (need_reinit) { //In case of rotation, the decoder needs to flushed in order to restart with the new video size AMediaCodec_flush(d->codec); d->first_buffer_queued = FALSE; } /*First put our H264 bitstream into the decoder*/ iBufidx = AMediaCodec_dequeueInputBuffer(d->codec, TIMEOUT_US); if (iBufidx >= 0) { buf = AMediaCodec_getInputBuffer(d->codec, iBufidx, &bufsize); if(buf == NULL) { ms_error("MSMediaCodecH264Dec: AMediaCodec_getInputBuffer() returned NULL"); break; } if((size_t)size > bufsize) { ms_error("Cannot copy the bitstream into the input buffer size : %i and bufsize %i",size,(int) bufsize); break; } else { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); memcpy(buf,d->bitstream,(size_t)size); AMediaCodec_queueInputBuffer(d->codec, iBufidx, 0, (size_t)size, (ts.tv_nsec/1000) + 10000LL, 0); d->first_buffer_queued = TRUE; } }else if (iBufidx == AMEDIA_ERROR_UNKNOWN){ ms_error("MSMediaCodecH264Dec: AMediaCodec_dequeueInputBuffer() had an exception"); } } d->packet_num++; if (d->sps && d->pps) request_pli = FALSE; else request_pli = TRUE; } /*secondly try to get decoded frames from the decoder, this is performed every tick*/ while (d->first_buffer_queued && (oBufidx = AMediaCodec_dequeueOutputBuffer(d->codec, &info, TIMEOUT_US)) >= 0){ AMediaFormat *format; int width = 0, height = 0, color = 0; uint8_t *buf = AMediaCodec_getOutputBuffer(d->codec, oBufidx, &bufsize); if(buf == NULL){ ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_DECODING_ERRORS); ms_error("MSMediaCodecH264Dec: AMediaCodec_getOutputBuffer() returned NULL"); } format = AMediaCodec_getOutputFormat(d->codec); if(format != NULL){ AMediaFormat_getInt32(format, "width", &width); AMediaFormat_getInt32(format, "height", &height); AMediaFormat_getInt32(format, "color-format", &color); d->vsize.width=width; d->vsize.height=height; AMediaFormat_delete(format); } if(buf != NULL && d->sps && d->pps){ /*some decoders output garbage while no sps or pps have been received yet !*/ if(width != 0 && height != 0 ){ if(color == 19) { //YUV int ysize = width*height; int usize = ysize/4; om = ms_yuv_buf_allocator_get(d->buf_allocator,&pic,width,height); memcpy(pic.planes[0],buf,ysize); memcpy(pic.planes[1],buf+ysize,usize); memcpy(pic.planes[2],buf+ysize+usize,usize); } else { uint8_t* cbcr_src = (uint8_t*) (buf + width * height); om = copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(d->buf_allocator, buf, cbcr_src, 0, width, height, width, width, TRUE, FALSE); } if (!d->first_image_decoded) { ms_message("First frame decoded %ix%i",width,height); d->first_image_decoded = true; ms_filter_notify_no_arg(f, MS_VIDEO_DECODER_FIRST_IMAGE_DECODED); } ms_queue_put(f->outputs[0], om); }else{ ms_error("MSMediaCodecH264Dec: width and height are not known !"); } } AMediaCodec_releaseOutputBuffer(d->codec, oBufidx, FALSE); } if (oBufidx == AMEDIA_ERROR_UNKNOWN){ ms_error("MSMediaCodecH264Dec: AMediaCodec_dequeueOutputBuffer() had an exception"); } if (d->avpf_enabled && request_pli) { ms_filter_notify_no_arg(f, MS_VIDEO_DECODER_SEND_PLI); } ms_queue_flush(f->inputs[0]); }
static GF_Err MCDec_ProcessData(GF_MediaDecoder *ifcg, char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 *CTS, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel) { MCDec *ctx = (MCDec *)ifcg->privateStack; ctx->nalu_size_length = 0; Bool mcdec_buffer_available = GF_FALSE; if (!ctx->reconfig_needed) MCDec_ParseNALs(ctx, inBuffer, inBufferLength, NULL, NULL); if (ctx->reconfig_needed) { if (ctx->raw_frame_dispatch && ctx->decoded_frames_pending) { *outBufferLength = 1; return GF_BUFFER_TOO_SMALL; } if (ctx->codec) { AMediaCodec_flush(ctx->codec); AMediaCodec_stop(ctx->codec); AMediaCodec_delete(ctx->codec); ctx->codec = NULL; } MCDec_InitDecoder(ctx); if (ctx->out_size != *outBufferLength) { *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } } if(!ctx->inputEOS) { ssize_t inIndex = AMediaCodec_dequeueInputBuffer(ctx->codec,ctx->dequeue_timeout); if (inIndex >= 0) { size_t inSize; char *buffer = (char *)AMediaCodec_getInputBuffer(ctx->codec, inIndex, &inSize); if (inBufferLength > inSize) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC,("The returned buffer is too small")); return GF_BUFFER_TOO_SMALL; } switch (ctx->esd->decoderConfig->objectTypeIndication) { case GPAC_OTI_VIDEO_AVC: memcpy(buffer, inBuffer, inBufferLength); break; case GPAC_OTI_VIDEO_HEVC: if(inBuffer[4] == 0x40) { //check for vps u32 start = ctx->vps_size + ctx->sps_size + ctx->pps_size; u32 i; for (i = start; i < inBufferLength ; ++i) { buffer[i - start] = inBuffer[i]; } buffer[0] = 0x00; buffer[1] = 0x00; buffer[2] = 0x00; buffer[3] = 0x01; } else { memcpy(buffer, inBuffer, inBufferLength); } break; default: memcpy(buffer, inBuffer, inBufferLength); break; } if(!inBuffer || inBufferLength == 0){ GF_LOG(GF_LOG_INFO, GF_LOG_CODEC,("AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM input")); ctx->inputEOS = GF_TRUE; } if(AMediaCodec_queueInputBuffer(ctx->codec, inIndex, 0, inBufferLength, *CTS, inBuffer ? 0 : AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM ) != AMEDIA_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC,("AMediaCodec_queueInputBuffer failed")); return GF_BAD_PARAM; } mcdec_buffer_available = GF_TRUE; } } if(!ctx->outputEOS) { ctx->outIndex = AMediaCodec_dequeueOutputBuffer(ctx->codec, &ctx->info, ctx->dequeue_timeout); *outBufferLength=0; switch(ctx->outIndex) { case AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED: GF_LOG(GF_LOG_INFO, GF_LOG_CODEC,("AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED")); ctx->format = AMediaCodec_getOutputFormat(ctx->codec); break; case AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED: GF_LOG(GF_LOG_INFO, GF_LOG_CODEC,("AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED")); break; case AMEDIACODEC_INFO_TRY_AGAIN_LATER: GF_LOG(GF_LOG_INFO, GF_LOG_CODEC,("AMEDIACODEC_INFO_TRY_AGAIN_LATER")); break; default: if (ctx->outIndex >= 0) { *CTS = ctx->info.presentationTimeUs; if(ctx->info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC,("AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM output")); ctx->outputEOS = true; } if(!ctx->surface_rendering) { size_t outSize; uint8_t * buffer = AMediaCodec_getOutputBuffer(ctx->codec, ctx->outIndex, &outSize); ctx->frame = buffer + ctx->info.offset; if(!ctx->frame) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC,("AMediaCodec_getOutputBuffer failed")); *outBufferLength = 0; } } if(ctx->surface_rendering || ctx->frame) { if(ctx->info.size < ctx->out_size) *outBufferLength = ctx->info.size; else *outBufferLength = ctx->out_size; } } break; } } return (mcdec_buffer_available) ? GF_OK : GF_CODEC_BUFFER_UNAVAILABLE; }
static void dec_process(MSFilter *f){ DecData *d=(DecData*)f->data; MSPicture pic = {0}; mblk_t *im,*om = NULL; bool_t need_reinit=FALSE; bool_t request_pli=FALSE; MSQueue nalus; ms_queue_init(&nalus); while((im=ms_queue_get(f->inputs[0]))!=NULL){ if (d->packet_num==0 && d->sps && d->pps){ mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im)); mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im)); rfc3984_unpack(&d->unpacker, d->sps, &nalus); rfc3984_unpack(&d->unpacker, d->pps, &nalus); d->sps=NULL; d->pps=NULL; } if(rfc3984_unpack(&d->unpacker,im,&nalus) <0){ request_pli=TRUE; } if (!ms_queue_empty(&nalus)){ AMediaCodecBufferInfo info; int size; int width = 0, height = 0, color = 0; uint8_t *buf=NULL; size_t bufsize; ssize_t iBufidx, oBufidx; size=nalusToFrame(d,&nalus,&need_reinit); if (need_reinit) { //In case of rotation, the decoder needs to flushed in order to restart with the new video size AMediaCodec_flush(d->codec); } iBufidx = AMediaCodec_dequeueInputBuffer(d->codec, TIMEOUT_US); if (iBufidx >= 0) { buf = AMediaCodec_getInputBuffer(d->codec, iBufidx, &bufsize); if(buf == NULL) { break; } if((size_t)size > bufsize) { ms_error("Cannot copy the bitstream into the input buffer size : %i and bufsize %i",size,(int) bufsize); } else { memcpy(buf,d->bitstream,(size_t)size); AMediaCodec_queueInputBuffer(d->codec, iBufidx, 0, (size_t)size, TIMEOUT_US, 0); } } oBufidx = AMediaCodec_dequeueOutputBuffer(d->codec, &info, TIMEOUT_US); if(oBufidx >= 0){ AMediaFormat *format; buf = AMediaCodec_getOutputBuffer(d->codec, oBufidx, &bufsize); if(buf == NULL){ ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_DECODING_ERRORS); break; } format = AMediaCodec_getOutputFormat(d->codec); if(format != NULL){ AMediaFormat_getInt32(format, "width", &width); AMediaFormat_getInt32(format, "height", &height); AMediaFormat_getInt32(format, "color-format", &color); d->vsize.width=width; d->vsize.height=height; AMediaFormat_delete(format); } } if(buf != NULL){ //YUV if(width != 0 && height != 0 ){ if(color == 19) { int ysize = width*height; int usize = ysize/4; om=ms_yuv_buf_alloc(&pic,width,height); memcpy(pic.planes[0],buf,ysize); memcpy(pic.planes[1],buf+ysize,usize); memcpy(pic.planes[2],buf+ysize+usize,usize); } else { uint8_t* cbcr_src = (uint8_t*) (buf + width * height); om = copy_ycbcrbiplanar_to_true_yuv_with_rotation_and_down_scale_by_2(d->buf_allocator, buf, cbcr_src, 0, width, height, width, width, TRUE, FALSE); } if (!d->first_image_decoded) { ms_message("First frame decoded %ix%i",width,height); d->first_image_decoded = true; ms_filter_notify_no_arg(f, MS_VIDEO_DECODER_FIRST_IMAGE_DECODED); } ms_queue_put(f->outputs[0], om); } if(oBufidx > 0) { AMediaCodec_releaseOutputBuffer(d->codec, oBufidx, FALSE); } } } d->packet_num++; } if (d->avpf_enabled && request_pli) { ms_filter_notify_no_arg(f, MS_VIDEO_DECODER_SEND_PLI); } }