static int demuxer_ffmpeg_read_frame (demuxer_wrapper_t * wrapper, dt_av_frame_t * frame) { dtdemuxer_context_t *dem_ctx = (dtdemuxer_context_t *) wrapper->parent; dt_media_info_t *media_info = &dem_ctx->media_info; int has_audio = (media_info->no_audio) ? 0 : media_info->has_audio; int has_video = (media_info->no_video) ? 0 : media_info->has_video; int has_sub = (media_info->no_sub) ? 0 : media_info->has_sub; int cur_aidx = (has_audio) ? media_info->astreams[media_info->cur_ast_index]->index : -1; int cur_vidx = (has_video) ? media_info->vstreams[media_info->cur_vst_index]->index : -1; int cur_sidx = (has_sub) ? media_info->sstreams[media_info->cur_sst_index]->index : -1; AVFormatContext *ic = (AVFormatContext *) wrapper->demuxer_priv; AVPacket avpkt; int ret = av_read_frame (ic, &avpkt); if (ret < 0) { if (AVERROR (EAGAIN) != ret) { /*if the return is EAGAIN,we need to try more times */ dt_warning (TAG, "[%s:%d]av_read_frame return (%d)\n", __FUNCTION__, __LINE__, ret); if (AVERROR_EOF != ret) return DTERROR_READ_FAILED; else return DTERROR_READ_EOF; } return DTERROR_READ_AGAIN; } //read frame ok if (has_video && cur_vidx == avpkt.stream_index) frame->type = AVMEDIA_TYPE_VIDEO; else if (has_audio && cur_aidx == avpkt.stream_index) frame->type = AVMEDIA_TYPE_AUDIO; else if (has_sub && cur_sidx == avpkt.stream_index) frame->type = AVMEDIA_TYPE_SUBTITLE; else { frame->type = AVMEDIA_TYPE_UNKNOWN; av_free_packet (&avpkt); return DTERROR_READ_AGAIN; // need to read again } //setup frame frame->data = avpkt.data; frame->size = avpkt.size; frame->pts = pts_exchange (&avpkt, media_info); frame->dts = avpkt.dts; frame->duration = avpkt.duration; dt_debug (TAG, "read ok,frame size:%d %02x %02x %02x %02x addr:%p\n", frame->size, frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data); dt_debug (TAG, "SIDE_DATA_ELEMENT:%d \n", avpkt.side_data_elems); return DTERROR_NONE; }
static void *audio_decode_loop (void *arg) { int ret; dtaudio_decoder_t *decoder = (dtaudio_decoder_t *) arg; dtaudio_para_t *para = &decoder->aparam; dt_av_frame_t frame; ad_wrapper_t *wrapper = decoder->wrapper; dtaudio_context_t *actx = (dtaudio_context_t *) decoder->parent; dt_buffer_t *out = &actx->audio_decoded_buf; int declen, fill_size; //for some type audio, can not read completly frame uint8_t *frame_data = NULL; // point to frame start uint8_t *rest_data = NULL; int frame_size = 0; int rest_size = 0; int used; // used size after every decode ops adec_ctrl_t *pinfo = &decoder->info; memset(pinfo,0,sizeof(*pinfo)); pinfo->channels = para->channels; pinfo->samplerate = para->samplerate; pinfo->outptr = malloc(MAX_ONE_FRAME_OUT_SIZE); pinfo->outsize = MAX_ONE_FRAME_OUT_SIZE; dt_info (TAG, "[%s:%d] AUDIO DECODE START \n", __FUNCTION__, __LINE__); do { //maybe receive exit cmd in idle status, so exit prior to idle if (decoder->status == ADEC_STATUS_EXIT) { dt_debug (TAG, "[%s:%d] receive decode loop exit cmd \n", __FUNCTION__, __LINE__); if (frame_data) free (frame_data); if (rest_data) free (rest_data); break; } if (decoder->status == ADEC_STATUS_IDLE) { dt_info (TAG, "[%s:%d] Idle status ,please wait \n", __FUNCTION__, __LINE__); usleep (100); continue; } /*read frame */ if (!decoder->parent) { usleep (10000); dt_info (TAG, "[%s:%d] decoder parent is NULL \n", __FUNCTION__, __LINE__); continue; } ret = audio_read_frame (decoder->parent, &frame); if (ret < 0 || frame.size <= 0) { usleep (1000); dt_debug (TAG, "[%s:%d] dtaudio decoder loop read frame failed \n", __FUNCTION__, __LINE__); continue; } //read ok,update current pts, clear the buffer size if (frame.pts >= 0) { if (decoder->pts_first == -1) { if(frame.pts == DT_NOPTS_VALUE) frame.pts = 0; decoder->pts_first = pts_exchange (decoder, frame.pts); dt_info (TAG, "first frame pts:%lld dts:%lld duration:%d size:%d\n", decoder->pts_first, frame.dts, frame.duration, frame.size); } decoder->pts_current = pts_exchange (decoder, frame.pts); dt_debug (TAG, "pkt pts:%lld current:%lld duration:%d pts_s:%lld dts:%lld buf_size:%d \n", frame.pts, decoder->pts_current, frame.duration, frame.pts / 90000, frame.dts, decoder->pts_buffer_size); decoder->pts_last_valid = decoder->pts_current; decoder->pts_buffer_size = 0; } //repack the frame if (frame_data) { free (frame_data); frame_data = NULL; frame_size = 0; } if (rest_size) frame_data = malloc (frame.size + rest_size); else frame_data = frame.data; if (!frame_data) { dt_error (TAG, "malloc audio frame failed ,we will lost one frame\n"); if (rest_data) free (rest_data); rest_size = 0; continue; } if (rest_size) // no rest data { dt_debug (TAG, "left %d byet last time\n", rest_size); memcpy (frame_data, rest_data, rest_size); free (rest_data); rest_data = NULL; memcpy (frame_data + rest_size, frame.data, frame.size); } frame_size = frame.size + rest_size; rest_size = 0; used = 0; declen = 0; pinfo->inptr = frame_data; pinfo->inlen = frame_size; pinfo->outlen = 0; //free pkt frame.data = NULL; frame.size = 0; DECODE_LOOP: if (decoder->status == ADEC_STATUS_EXIT) { dt_info (TAG, "[%s:%d] receive decode loop exit cmd \n", __FUNCTION__, __LINE__); if (frame_data) free (frame_data); break; } /*decode frame */ pinfo->consume = declen; used = wrapper->decode_frame (wrapper, pinfo); if (used < 0) { decoder->decode_err_cnt++; /* * if decoder is ffmpeg,do not restore data if decode failed * if decoder is not ffmpeg, restore raw stream packet if decode failed * */ if (!strcmp (wrapper->name, "ffmpeg audio decoder")) { dt_error (TAG, "[%s:%d] ffmpeg failed to decode this frame, just break\n", __FUNCTION__, __LINE__); decoder->decode_offset += pinfo->inlen; } continue; } else if (used == 0 && pinfo->outlen == 0) // used == 0 && out == 0 means need more data { //maybe need more data rest_data = malloc (pinfo->inlen); if (rest_data == NULL) { dt_error ("[%s:%d] rest_data malloc failed\n", __FUNCTION__, __LINE__); rest_size = 0; //skip this frame continue; } memcpy (rest_data, pinfo->inptr, pinfo->inlen); rest_size = pinfo->inlen; dt_info (TAG, "Maybe we need more data\n"); continue; } declen += used; pinfo->inlen -= used; decoder->decode_offset += used; decoder->pts_cache_size = pinfo->outlen; decoder->pts_buffer_size += pinfo->outlen; if (pinfo->outlen == 0) //get no data, maybe first time for init dt_info (TAG, "GET NO PCM DECODED OUT,used:%d \n",used); fill_size = 0; REFILL_BUFFER: if (decoder->status == ADEC_STATUS_EXIT) goto EXIT; /*write pcm */ if (buf_space (out) < pinfo->outlen) { dt_debug (TAG, "[%s:%d] output buffer do not left enough space ,space=%d level:%d outsie:%d \n", __FUNCTION__, __LINE__, buf_space (out), buf_level (out), pinfo->outlen); usleep (1000); goto REFILL_BUFFER; } ret = buf_put (out, pinfo->outptr + fill_size, pinfo->outlen); fill_size += ret; pinfo->outlen -= ret; decoder->pts_cache_size = pinfo->outlen; if (pinfo->outlen > 0) goto REFILL_BUFFER; if (pinfo->inlen) goto DECODE_LOOP; } while (1); EXIT: dt_info (TAG, "[file:%s][%s:%d]decoder loop thread exit ok\n", __FILE__, __FUNCTION__, __LINE__); /* free adec_ctrl_t buf */ if(pinfo->outptr) free(pinfo->outptr); pinfo->outlen = pinfo->outsize = 0; pthread_exit (NULL); return NULL; }
static void *video_decode_loop (void *arg) { dt_av_frame_t frame; dtvideo_decoder_t *decoder = (dtvideo_decoder_t *) arg; vd_wrapper_t *wrapper = decoder->wrapper; dtvideo_context_t *vctx = (dtvideo_context_t *) decoder->parent; queue_t *picture_queue = vctx->vo_queue; /*used for decode */ AVPicture_t *picture = NULL; int ret; dt_info (TAG, "[%s:%d] start decode loop \n", __FUNCTION__, __LINE__); do { if (decoder->status == VDEC_STATUS_IDLE) { dt_info (TAG, "[%s:%d] Idle status ,please wait \n", __FUNCTION__, __LINE__); usleep (100); continue; } if (decoder->status == VDEC_STATUS_EXIT) { dt_info (TAG, "[%s:%d] receive decode loop exit cmd \n", __FUNCTION__, __LINE__); break; } /*read frame */ if (!decoder->parent) { usleep (100); continue; } if (picture_queue->length >= VIDEO_OUT_MAX_COUNT) { //vo queue full usleep (1000); continue; } ret = dtvideo_read_frame (decoder->parent, &frame); if (ret < 0) { usleep (100); dt_debug (TAG, "[%s:%d] dtaudio decoder loop read frame failed \n", __FUNCTION__, __LINE__); continue; } /*read one frame,enter decode frame module */ //will exec once for one time ret = wrapper->decode_frame (wrapper, &frame, &picture); if (ret <= 0) { decoder->decode_err_cnt++; dt_debug (TAG, "[%s:%d]decode failed \n", __FUNCTION__, __LINE__); picture = NULL; goto DECODE_END; } if (!picture) goto DECODE_END; decoder->frame_count++; //Got one frame //picture->pts = frame.pts; //update current pts, clear the buffer size if (frame.pts >= 0 && decoder->pts_first == -1) { //we will use first pts to estimate pts dt_info (TAG, "[%s:%d]first frame decoded ok, pts:0x%x dts:0x%x duration:%d size:%d\n", __FUNCTION__, __LINE__, frame.pts, frame.dts, frame.duration, frame.size); decoder->pts_first = pts_exchange (decoder, picture->pts); decoder->pts_current = decoder->pts_first; } else { if(pts_mode) { int fps = decoder->para.fps; float dur_inc = 90000/fps; picture->pts = decoder->pts_current + dur_inc; decoder->pts_current = picture->pts; } } /*queue in */ queue_push_tail (picture_queue, picture); picture = NULL; DECODE_END: //we successfully decodec one frame if (frame.data) { free (frame.data); frame.data = NULL; frame.size = 0; frame.pts = -1; } } while (1); dt_info (TAG, "[file:%s][%s:%d]decoder loop thread exit ok\n", __FILE__, __FUNCTION__, __LINE__); pthread_exit (NULL); return NULL; }
static void *video_decode_loop (void *arg) { dt_av_pkt_t frame; dtvideo_decoder_t *decoder = (dtvideo_decoder_t *) arg; vd_wrapper_t *wrapper = decoder->wrapper; dtvideo_context_t *vctx = (dtvideo_context_t *) decoder->parent; dtvideo_filter_t *filter = (dtvideo_filter_t *) &(vctx->video_filt); queue_t *picture_queue = vctx->vo_queue; /*used for decode */ dt_av_frame_t *picture = NULL; int ret; dt_info (TAG, "[%s:%d] start decode loop \n", __FUNCTION__, __LINE__); do { //exit check before idle, maybe recieve exit cmd in idle status if (decoder->status == VDEC_STATUS_EXIT) { dt_info (TAG, "[%s:%d] receive decode loop exit cmd \n", __FUNCTION__, __LINE__); break; } if (decoder->status == VDEC_STATUS_IDLE) { dt_info (TAG, "[%s:%d] Idle status ,please wait \n", __FUNCTION__, __LINE__); usleep (100); continue; } /*read frame */ if (!decoder->parent) { usleep (100); continue; } if (picture_queue->length >= VIDEO_OUT_MAX_COUNT) { //vo queue full usleep (1000); continue; } ret = dtvideo_read_frame (decoder->parent, &frame); if (ret < 0) { if(decoder->pts_first == -1 || decoder->pts_first == DT_NOPTS_VALUE) { usleep(1000); continue; } //no data left, maybe eof, need to flush left data memset(&frame,0,sizeof(dt_av_pkt_t)); dt_info (TAG, "[%s:%d] no video frame left, flush left frames \n", __FUNCTION__, __LINE__); } /*read one frame,enter decode frame module */ //will exec once for one time ret = wrapper->decode_frame (decoder, &frame, &picture); if (ret <= 0) { decoder->decode_err_cnt++; dt_info (TAG, "[%s:%d]decode failed \n", __FUNCTION__, __LINE__); picture = NULL; usleep(10000); goto DECODE_END; } if (!picture) goto DECODE_END; //got one frame, filter process if(wrapper->info_changed(decoder)) { memcpy(&decoder->para, &wrapper->para, sizeof(dtvideo_para_t)); memcpy(&filter->para, &wrapper->para, sizeof(dtvideo_para_t)); video_filter_reset(filter, &decoder->para); } video_filter_process(filter, picture); decoder->frame_count++; //Got one frame //picture->pts = frame.pts; //update current pts, clear the buffer size if (frame.pts >= 0 && decoder->pts_first == -1) { //we will use first pts to estimate pts dt_info (TAG, "[%s:%d]first frame decoded ok, pts:0x%llx dts:0x%llx duration:%d size:%d\n", __FUNCTION__, __LINE__, frame.pts, frame.dts, frame.duration, frame.size); decoder->pts_first = pts_exchange (decoder, picture->pts); decoder->pts_current = decoder->pts_first; } else { if(pts_mode) { int fps = decoder->para.fps; float dur_inc = 90000/fps; picture->pts = decoder->pts_current + dur_inc; decoder->pts_current = picture->pts; } } /*queue in */ queue_push_tail (picture_queue, picture); picture = NULL; DECODE_END: //we successfully decodec one frame if (frame.data) { if(frame.data) free (frame.data); frame.data = NULL; frame.size = 0; frame.pts = -1; } } while (1); dt_info (TAG, "[file:%s][%s:%d]decoder loop thread exit ok\n", __FILE__, __FUNCTION__, __LINE__); //filter release video_filter_stop(filter); pthread_exit (NULL); return NULL; }
static void *video_decode_loop(void *arg) { dt_av_pkt_t frame; dtvideo_decoder_t *decoder = (dtvideo_decoder_t *) arg; vd_wrapper_t *wrapper = decoder->wrapper; vd_statistics_info_t *p_vd_statistics_info = &decoder->statistics_info; dtvideo_context_t *vctx = (dtvideo_context_t *) decoder->parent; queue_t *picture_queue = vctx->vo_queue; /*used for decode */ dt_av_frame_t *picture = NULL; int ret; dt_info(TAG, "[%s:%d] start decode loop \n", __FUNCTION__, __LINE__); do { //exit check before idle, maybe recieve exit cmd in idle status if (decoder->status == VDEC_STATUS_EXIT) { dt_info(TAG, "[%s:%d] receive decode loop exit cmd \n", __FUNCTION__, __LINE__); break; } if (decoder->status == VDEC_STATUS_IDLE) { dt_info(TAG, "[%s:%d] Idle status ,please wait \n", __FUNCTION__, __LINE__); usleep(100); continue; } /*read frame */ if (!decoder->parent) { usleep(100); continue; } if (picture_queue->length >= VIDEO_OUT_MAX_COUNT) { //vo queue full usleep(1000); continue; } ret = dtvideo_read_frame(decoder->parent, &frame); if (ret < 0) { dt_usleep(1000); if (decoder->pts_first == DT_NOPTS_VALUE) { continue; } //no data left, maybe eof, need to flush left data memset(&frame, 0, sizeof(dt_av_pkt_t)); dt_debug(TAG, "[%s:%d] no video frame left, flush left frames \n", __FUNCTION__, __LINE__); } /*read one frame,enter decode frame module */ //will exec once for one time ret = wrapper->decode_frame(decoder, &frame, &picture); if (ret <= 0) { decoder->decode_err_cnt++; dt_debug(TAG, "[%s:%d]decode failed \n", __FUNCTION__, __LINE__); picture = NULL; //usleep(10000); goto DECODE_END; } if (!picture) { goto DECODE_END; } // statistics collection { p_vd_statistics_info->decoded_frame_count++; } decoder->frame_count++; //Got one frame //update current pts, clear the buffer size if (PTS_VALID(picture->pts)) { picture->pts = pts_exchange(decoder, picture->pts); } if (decoder->first_frame_decoded == 0 && PTS_INVALID(decoder->pts_first)) { decoder->pts_first = decoder->pts_current = picture->pts; decoder->first_frame_decoded = 1; dt_info(TAG, "[%s:%d]first frame decoded ok, pts:0x%llx dts:0x%llx\n", __FUNCTION__, __LINE__, picture->pts, picture->dts); } else { if (pts_mode || PTS_INVALID(picture->pts)) { int fps = decoder->para.fps; int dur_inc = (int)((double)90000 / fps); picture->pts = decoder->pts_current + dur_inc; decoder->pts_current = picture->pts; dt_debug(TAG, "vpts inc itself. pts_mode:%d pts:0x%llx inc:%d\n", pts_mode, picture->pts, dur_inc); } } /*queue in */ queue_push_tail(picture_queue, picture); picture = NULL; DECODE_END: //we successfully decodec one frame if (frame.data) { if (frame.data) { free(frame.data); } frame.data = NULL; frame.size = 0; frame.pts = -1; } } while (1); dt_info(TAG, "[file:%s][%s:%d]decoder loop thread exit ok\n", __FILE__, __FUNCTION__, __LINE__); pthread_exit(NULL); return NULL; }