static void enc_process(MSFilter *f){
	EncData *d=(EncData*)f->data;
	MSPicture pic = {0};
	MSQueue nalus;
	mblk_t *im;
	long long int ts = f->ticker->time * 90LL;

	if (d->codec==NULL){
		ms_queue_flush(f->inputs[0]);
		return;
	}

	ms_queue_init(&nalus);
    while((im=ms_queue_get(f->inputs[0]))!=NULL){
		if (ms_yuv_buf_init_from_mblk(&pic,im)==0){
			uint8_t *buf=NULL;
        	size_t bufsize;
        	ssize_t ibufidx, obufidx;

			ibufidx = AMediaCodec_dequeueInputBuffer(d->codec, TIMEOUT_US);
			if (ibufidx >= 0) {
				buf = AMediaCodec_getInputBuffer(d->codec, ibufidx, &bufsize);
				if(buf != NULL){
					if(d->isYUV){
						int ysize = pic.w * pic.h;
						int usize = ysize / 4;
						memcpy(buf, pic.planes[0], ysize);
						memcpy(buf + ysize, pic.planes[1], usize);
						memcpy(buf + ysize+usize, pic.planes[2], usize);
					} else {
						size_t size=(size_t) pic.w * pic.h;
						uint8_t *dst = pic.planes[0];
						memcpy(buf,dst,size);
						int i;

						for (i = 0; i < pic.w/2*pic.h/2; i++){
							buf[size+2*i]=pic.planes[1][i];
							buf[size+2*i+1]=pic.planes[2][i];
						}
					}
					AMediaCodec_queueInputBuffer(d->codec, ibufidx, 0, (size_t)(pic.w * pic.h)*3/2, f->ticker->time*1000,0);
				}
			}

			AMediaCodecBufferInfo info;
            obufidx = AMediaCodec_dequeueOutputBuffer(d->codec, &info, TIMEOUT_US);
            while(obufidx >= 0) {
				buf = AMediaCodec_getOutputBuffer(d->codec, obufidx, &bufsize);
				extractNalus(buf,info.size,ts,&nalus);
                AMediaCodec_releaseOutputBuffer(d->codec, obufidx, FALSE);
				obufidx = AMediaCodec_dequeueOutputBuffer(d->codec, &info, TIMEOUT_US);
				rfc3984_pack(d->packer,&nalus,f->outputs[0],ts);
			}


			if (d->framenum==0)
            	ms_video_starter_first_frame(&d->starter, f->ticker->time);
            d->framenum++;

		}
		freemsg(im);
	}


	if (d->force_keyframe == TRUE) {
		AMediaCodec_setParams(d->codec,"");
		d->force_keyframe = FALSE;
	}
}
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 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);
    }
}
Example #4
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;      
}
void doCodecWork(workerdata *d)
{

   ssize_t bufidx = -1;
   if (!d->sawInputEOS)
   {
      bufidx = AMediaCodec_dequeueInputBuffer(d->codec, 2000);
      //LOGV("input buffer %zd", bufidx);
      if (bufidx >= 0)
      {
         size_t bufsize;
         uint8_t *buf = AMediaCodec_getInputBuffer(d->codec, bufidx, &bufsize);
         ssize_t sampleSize = AMediaExtractor_readSampleData(d->ex, buf, bufsize);
         //LOGV("\tinput buffer size %zd", sampleSize);
         if (sampleSize < 0)
         {
            sampleSize = 0;
            d->sawInputEOS = true;
            LOGV("EOS EOS EOS EOS EOS EOS EOS EOS EOS EOS");
         }
         int64_t presentationTimeUs = AMediaExtractor_getSampleTime(d->ex);

         //AMediaCodec_queueInputBuffer(d->codec, bufidx, 0, sampleSize, presentationTimeUs, d->sawInputEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
         AMediaCodec_queueInputBuffer(d->codec, bufidx, 0, sampleSize, presentationTimeUs, 0);
         AMediaExtractor_advance(d->ex);
      }
   }

   if (!d->sawOutputEOS)
   {
      AMediaCodecBufferInfo info;
      ssize_t status = AMediaCodec_dequeueOutputBuffer(d->codec, &info, 0);
      if (status >= 0)
      {
         if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
         {
            LOGV("output EOS");
            d->sawOutputEOS = true;
         }
         int64_t presentationNano = info.presentationTimeUs * 1000;
         if (d->renderstart < 0)
         {
            d->renderstart = systemnanotime() - presentationNano;
         }
         int64_t delay = (d->renderstart + presentationNano) - systemnanotime();
         if (delay > 0)
         {
            usleep(delay / 1000);
         }
         AMediaCodec_releaseOutputBuffer(d->codec, status, info.size != 0);
         if (d->renderonce)
         {
            d->renderonce = false;
            return;
         }
      }
      else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
      {
         LOGV("output buffers changed");
      }
      else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
      {
         AMediaFormat *format = NULL;
         format = AMediaCodec_getOutputFormat(d->codec);
         LOGV("format changed to: %s", AMediaFormat_toString(format));
         AMediaFormat_delete(format);
      }
      else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
      {
         //LOGV("no output buffer right now");
      }
      else
      {
         LOGV("unexpected info code: %zd", status);
      }
   }

   if (!d->sawInputEOS || !d->sawOutputEOS)
   {
      if (d->sawInputEOS == true)
      {
         seeked = true;
         mlooper->post(kMsgSeek, d);
      }
      else
         mlooper->post(kMsgCodecBuffer, d);
   }
}