static void enc_preprocess(MSFilter* f) { EncData *d=(EncData*)f->data; d->packer=rfc3984_new(); rfc3984_set_mode(d->packer,d->mode); rfc3984_enable_stap_a(d->packer,FALSE); ms_video_starter_init(&d->starter); AMediaCodec *codec; codec = AMediaCodec_createEncoderByType("video/avc"); d->codec = codec; AMediaFormat *format = AMediaFormat_new(); AMediaFormat_setString(format, "mime", "video/avc"); AMediaFormat_setInt32(format, "width", d->vconf.vsize.width); AMediaFormat_setInt32(format, "height", d->vconf.vsize.height); AMediaFormat_setInt32(format, "i-frame-interval", 20); AMediaFormat_setInt32(format, "color-format", 19); AMediaFormat_setInt32(format, "bitrate", d->vconf.required_bitrate); AMediaFormat_setInt32(format, "frame-rate", d->vconf.fps); AMediaFormat_setInt32(format, "bitrate-mode",1); media_status_t status = AMediaCodec_configure(d->codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); if(status != 0){ d->isYUV = FALSE; AMediaFormat_setInt32(format, "color-format", 21); AMediaCodec_configure(d->codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); } AMediaCodec_start(d->codec); AMediaFormat_delete(format); }
static void dec_init(MSFilter *f){ AMediaFormat *format; AMediaCodec *codec = AMediaCodec_createDecoderByType("video/avc"); DecData *d=ms_new0(DecData,1); d->codec = codec; d->sps=NULL; d->pps=NULL; rfc3984_init(&d->unpacker); d->packet_num=0; d->vsize.width=0; d->vsize.height=0; d->bitstream_size=65536; d->avpf_enabled=FALSE; d->bitstream=ms_malloc0(d->bitstream_size); d->buf_allocator = ms_yuv_buf_allocator_new(); ms_average_fps_init(&d->fps, " H264 decoder: FPS: %f"); 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(codec, format, NULL, NULL, 0); AMediaCodec_start(codec); AMediaFormat_delete(format); f->data=d; }
void DeleteMCDec(GF_BaseDecoder *ifcg) { MCDec *ctx = (MCDec *)ifcg->privateStack; if(ctx->format && AMediaFormat_delete(ctx->format) != AMEDIA_OK){ GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC,("AMediaFormat_delete failed")); } if(ctx->codec && AMediaCodec_delete(ctx->codec) != AMEDIA_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC,("AMediaCodec_delete failed")); } if(ctx->window) { ANativeWindow_release(ctx->window); ctx->window = NULL; } gf_free(ctx); gf_free(ifcg); MCDec_DelParamList(ctx->SPSs); ctx->SPSs = NULL; MCDec_DelParamList(ctx->PPSs); ctx->PPSs = NULL; }
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 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); } }
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); } }
jboolean Java_com_example_nativecodec_NativeCodec_createStreamingMediaPlayer(JNIEnv *env, jclass clazz, jstring filename) { LOGV("@@@ create"); // convert Java string to UTF-8 const char *utf8 = env->GetStringUTFChars(filename, NULL); LOGV("opening %s", utf8); int fd = open(utf8, O_RDONLY); env->ReleaseStringUTFChars(filename, utf8); if (fd < 0) { LOGV("failed: %d (%s)", fd, strerror(errno)); return JNI_FALSE; } data.fd = fd; workerdata *d = &data; AMediaExtractor *ex = AMediaExtractor_new(); media_status_t err = AMediaExtractor_setDataSourceFd(ex, d->fd, 0, LONG_MAX); close(d->fd); if (err != AMEDIA_OK) { LOGV("setDataSource error: %d", err); return JNI_FALSE; } int numtracks = AMediaExtractor_getTrackCount(ex); AMediaCodec *codec = NULL; LOGV("input has %d tracks", numtracks); for (int i = 0; i < numtracks; i++) { AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i); const char *s = AMediaFormat_toString(format); LOGV("track %d format: %s", i, s); const char *mime; if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) { LOGV("no mime type"); return JNI_FALSE; } else if (!strncmp(mime, "video/", 6)) { // Omitting most error handling for clarity. // Production code should check for errors. AMediaExtractor_selectTrack(ex, i); codec = AMediaCodec_createDecoderByType(mime); AMediaCodec_configure(codec, format, d->window, NULL, 0); d->ex = ex; d->codec = codec; d->renderstart = -1; d->sawInputEOS = false; d->sawOutputEOS = false; d->isPlaying = false; d->renderonce = true; AMediaCodec_start(codec); } AMediaFormat_delete(format); } mlooper = new mylooper(); mlooper->post(kMsgCodecBuffer, d); return JNI_TRUE; }