//1 get one frame 0 failed -1 err int ffmpeg_adec_decode(ad_wrapper_t *wrapper, adec_ctrl_t *pinfo) { int got_samples = 0; int ret = 0; int data_size = 0; AVFrame frame_tmp; //AVFrame frame; AVPacket pkt; memset(&pkt, 0, sizeof(AVPacket)); pkt.data = pinfo->inptr; pkt.size = pinfo->inlen; pkt.side_data_elems = 0; memset(&frame_tmp, 0, sizeof(AVFrame)); memset(frame, 0, sizeof(AVFrame)); dtaudio_decoder_t *decoder = (dtaudio_decoder_t *)wrapper->parent; dt_debug(TAG, "start decode size:%d %02x %02x \n", pkt.size, pkt.data[0], pkt.data[1]); ret = avcodec_decode_audio4(avctxp, frame, &got_samples, &pkt); dt_debug(TAG, "start decode size:%d %02x %02x %02x %02x \n", pkt.size, pkt.data[0], pkt.data[1], pkt.data[2], pkt.data[3]); if (ret < 0) { dt_error(TAG, "decode failed ret:%d \n", ret); goto EXIT; } if (!got_samples) { //decode return 0 dt_error(TAG, "get no samples out \n"); pinfo->outlen = 0; goto EXIT; } data_size = av_samples_get_buffer_size(frame->linesize, avctxp->channels, frame->nb_samples, avctxp->sample_fmt, 1); if (data_size > 0) { audio_convert(decoder, &frame_tmp, frame); //out frame too large, realloc out buf if (pinfo->outsize < frame_tmp.linesize[0]) { pinfo->outptr = realloc(pinfo->outptr, frame_tmp.linesize[0] * 2); pinfo->outsize = frame_tmp.linesize[0] * 2; } memcpy(pinfo->outptr, frame_tmp.data[0], frame_tmp.linesize[0]); pinfo->outlen = frame_tmp.linesize[0]; } else { dt_error(TAG, "data_size invalid: size:%d outlen:%d \n", data_size, pinfo->outlen); pinfo->outlen = 0; } EXIT: if (frame_tmp.data[0]) { free(frame_tmp.data[0]); } frame_tmp.data[0] = NULL; return ret; }
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; }
int main() { dt_get_log_level(); dt_info("TEST", "this is info level test \n"); dt_error("TEST", "this is error level test \n"); dt_debug("TEST", "this is debug level test \n"); dt_warning("TEST", "this is warnning level test \n"); dt_set_log_level(1); dt_info("TEST", "this is info level test \n"); dt_error("TEST", "this is error level test \n"); dt_debug("TEST", "this is debug level test \n"); dt_warning("TEST", "this is warning level test \n"); return; }
int64_t video_get_first_pts (dtvideo_context_t * vctx) { if (vctx->video_status != VIDEO_STATUS_INITED) return -1; dt_debug (TAG, "fitst vpts:%lld \n", vctx->video_dec.pts_first); return vctx->video_dec.pts_first; }
int dthost_init (void **host_priv, dthost_para_t * para) { int ret = 0; if (*host_priv) { dt_error (TAG, "[%s:%d] host_priv is Null\n", __FUNCTION__, __LINE__); ret = -1; goto ERR0; } dthost_context_t *hctx = malloc (sizeof (dthost_context_t)); if (!hctx) { dt_info (TAG, "[%s:%d] dthost_context_t malloc failed\n", __FUNCTION__, __LINE__); ret = -1; goto ERR0; } dt_debug (TAG, "hctx :%p \n", hctx); memset (hctx, 0, sizeof (dthost_context_t)); memcpy (&hctx->para, para, sizeof (dthost_para_t)); ret = host_init (hctx); if (ret < 0) { dt_error (TAG, "[%s:%d] dthost_init failed\n", __FUNCTION__, __LINE__); ret = -1; goto ERR1; } *host_priv = (void *) hctx; return ret; ERR1: free (hctx); ERR0: return ret; }
int dt_send_event (event_t * event) { dt_server_mgt_t *mgt = &server_mgt; event_server_t *server_hub = mgt->server; if (!server_hub) { dt_error (TAG, "EVENT SEND FAILED \n"); return -1; } dt_lock (&server_hub->event_lock); if (server_hub->event_count == 0) server_hub->event = event; else { event_t *entry = server_hub->event; while (entry->next) entry = entry->next; entry->next = event; } server_hub->event_count++; dt_unlock (&server_hub->event_lock); dt_debug (TAG, "EVENT:%d SEND OK, event count:%d \n", event->type, server_hub->event_count); return 0; }
int dthost_start (void *host_priv) { int ret = 0; dthost_context_t *hctx = (dthost_context_t *) host_priv; dt_debug (TAG, "hctx :%p \n", hctx); ret = host_start (hctx); return ret; }
static void audio_convert(dtaudio_decoder_t *decoder, AVFrame * dst, AVFrame * src) { int nb_sample; int dst_buf_size; int out_channels; //for audio post processor //struct SwsContext *m_sws_ctx = NULL; struct SwrContext *m_swr_ctx = NULL; //ResampleContext *m_resample_ctx=NULL; enum AVSampleFormat src_fmt = avctxp->sample_fmt; enum AVSampleFormat dst_fmt = AV_SAMPLE_FMT_S16; dst->linesize[0] = src->linesize[0]; *dst = *src; dst->data[0] = NULL; out_channels = decoder->para.dst_channels; nb_sample = frame->nb_samples; dst_buf_size = nb_sample * av_get_bytes_per_sample(dst_fmt) * out_channels; dst->data[0] = (uint8_t *) av_malloc(dst_buf_size); avcodec_fill_audio_frame(dst, out_channels, dst_fmt, dst->data[0], dst_buf_size, 0); dt_debug(TAG, "SRCFMT:%d dst_fmt:%d \n", src_fmt, dst_fmt); /* resample toAV_SAMPLE_FMT_S16 */ if (src_fmt != dst_fmt || out_channels != decoder->para.channels) { if (!m_swr_ctx) { uint64_t in_channel_layout = av_get_default_channel_layout(avctxp->channels); uint64_t out_channel_layout = av_get_default_channel_layout(out_channels); m_swr_ctx = swr_alloc_set_opts(NULL, out_channel_layout, dst_fmt, avctxp->sample_rate, in_channel_layout, src_fmt, avctxp->sample_rate, 0, NULL); swr_init(m_swr_ctx); } uint8_t **out = (uint8_t **) & dst->data; const uint8_t **in = (const uint8_t **) src->extended_data; if (m_swr_ctx) { int ret, out_count; out_count = nb_sample; ret = swr_convert(m_swr_ctx, out, out_count, in, nb_sample); if (ret < 0) { //set audio mute memset(dst->data[0], 0, dst_buf_size); printf("audio convert failed, set mute data\n"); } } } else { // no need to convert ,just copy memcpy(dst->data[0], src->data[0], src->linesize[0]); } //free context if (m_swr_ctx != NULL) { swr_free(&m_swr_ctx); } //if(m_resample_ctx!=NULL) // audio_resample_close(m_resample_ctx); }
int64_t audio_decoder_get_pts (dtaudio_decoder_t * decoder) { int64_t pts, delay_pts; int frame_num; int channels, sample_rate, bps; int len; float pts_ratio; dtaudio_context_t *actx = (dtaudio_context_t *) decoder->parent; dt_buffer_t *out = &actx->audio_decoded_buf; if (decoder->status == ADEC_STATUS_IDLE || decoder->status == ADEC_STATUS_EXIT) return -1; channels = decoder->aparam.dst_channels; sample_rate = decoder->aparam.samplerate; bps = decoder->aparam.bps; pts_ratio = (float) DTAUDIO_PTS_FREQ / sample_rate; pts = 0; if (-1 == decoder->pts_first) return -1; if (-1 == decoder->pts_current) //case 1 current_pts valid { //if(decoder->pts_last_valid) // pts=decoder->pts_last_valid; //len = decoder->pts_cache_size + decoder->pts_buffer_size - out->level; len = decoder->pts_buffer_size; frame_num = (len) / (bps * channels / 8); pts += (frame_num) * pts_ratio; pts += decoder->pts_first; dt_debug (TAG, "[%s:%d] first_pts:%llu pts:%llu pts_s:%d frame_num:%d len:%d pts_ratio:%5.1f\n", __FUNCTION__, __LINE__, decoder->pts_first, pts, pts / 90000, frame_num, len, pts_ratio); return pts; } //case 2 current_pts invalid,calc pts mentally pts = decoder->pts_current; len = decoder->pts_buffer_size - out->level - decoder->pts_cache_size; frame_num = (len) / (bps * channels / 8); delay_pts = (frame_num) * pts_ratio; dt_debug (TAG, "[%s:%d] current_pts:%lld delay_pts:%lld pts_s:%lld frame_num:%d pts_ratio:%f\n", __FUNCTION__, __LINE__, decoder->pts_current, delay_pts, pts / 90000, frame_num, pts_ratio); pts += delay_pts; if (pts < 0) pts = 0; return pts; }
static int stream_cache_seek (stream_wrapper_t * wrapper, int64_t pos, int whence) { int ret = 0; cache_ctx_t *ctx = (cache_ctx_t *)wrapper->stream_priv; stream_cache_t *cache = ctx->cache; stream_wrapper_t *real_st = ctx->wrapper; stream_ctrl_t *info = &wrapper->info; info->eof_flag = 0; dt_info(TAG,"Enter cache seek \n"); // ret stream size if(whence == AVSEEK_SIZE) { dt_debug(TAG,"REQUEST STREAM SIZE:%lld \n",info->stream_size); return info->stream_size; } int step; int orig; if(whence == SEEK_SET) { step = abs(info->cur_pos - pos); orig = (info->cur_pos > pos)?0:1; } if(whence == SEEK_CUR) { step = abs(pos); orig = (pos < 0)?0:1; } if(cache_seek(cache,step,orig) == 0) // seek in cache { dt_info(TAG,"cache seek success \n"); } else // seek through real stream ops { pause_cache_thread(ctx); ret =real_st->seek(real_st,pos,whence); // fixme: seek maybe failed for online video if(ret != DTERROR_NONE) { dt_error(TAG,"SEEK FAILED \n"); } cache_reset(ctx->cache); resume_cache_thread(ctx); } info->eof_flag = 0; if(whence == SEEK_SET) info->cur_pos = pos; if(whence == SEEK_CUR) info->cur_pos += pos; return ret; }
int dt_send_event_sync (event_t * event) { dt_server_mgt_t *mgt = &server_mgt; event_server_t *server_hub = mgt->server; if (!server_hub) { dt_error (TAG, "EVENT SEND FAILED \n"); return -1; } dt_transport_event (event, mgt); dt_debug (TAG, "EVENT:%d BYPASS SEND OK \n"); return 0; }
static int ao_alsa_play(dtaudio_output_t *aout, uint8_t * buf, int size) { alsa_ctx_t *ctx = (alsa_ctx_t *)wrapper->ao_priv; snd_pcm_t *alsa_handle = (snd_pcm_t *) ctx->handle; int bytes_per_sample = wrapper->para.bps * wrapper->para.dst_channels / 8; int num_frames = size / bytes_per_sample; snd_pcm_sframes_t res = 0; uint8_t *data = buf; if (!alsa_handle) { return -1; } if (num_frames == 0) { return 0; } if (ao_alsa_level(aout) >= ctx->buf_threshold) { dt_debug(TAG, "ALSA EXCEED THRESHOLD,size:%d thres:%d \n", ao_alsa_level(aout), ctx->buf_threshold); return 0; } res = snd_pcm_writei(alsa_handle, data, num_frames); if (res == -EINTR) { dt_info(TAG, "ALSA HAS NO SPACE, WRITE AGAIN\n"); return res; } if (res == -ESTRPIPE) { snd_pcm_resume(alsa_handle); return res; } if (res == -EBADFD) { snd_pcm_reset(alsa_handle); return res; } if (res < 0) { snd_pcm_prepare(alsa_handle); dt_info(TAG, "snd pcm write failed prepare!\n"); return -1; //goto rewrite; } if (res < num_frames) { data += res * bytes_per_sample; num_frames -= res; //goto rewrite; } return res * bytes_per_sample; }
static int stream_ffmpeg_seek(stream_wrapper_t * wrapper, int64_t pos, int whence) { AVIOContext *ctx = (AVIOContext *)wrapper->stream_priv; stream_ctrl_t *info = &wrapper->info; info->eof_flag = 0; if (whence == AVSEEK_SIZE) { dt_debug(TAG, "REQUEST STREAM SIZE:%lld \n", info->stream_size); return avio_size(ctx); } return avio_seek(ctx, pos, whence); }
static int stream_file_read(stream_wrapper_t * wrapper, uint8_t *buf, int len) { file_ctx_t *ctx = (file_ctx_t *)wrapper->stream_priv; stream_ctrl_t *info = &wrapper->info; int r = read(ctx->fd, buf, len); dt_debug(TAG, "read %d byte \n", len); if (r > 0) { info->cur_pos += r; } if (r <= 0) { info->eof_flag = 1; } return (r <= 0) ? -1 : r; }
static int update_cb (player_state_t * state) { if (state->cur_status == PLAYER_STATUS_EXIT) { dt_info (TAG, "RECEIVE EXIT CMD\n"); ply_ctx.exit_flag = 1; } ply_ctx.cur_time = state->cur_time; ply_ctx.cur_time_ms = state->cur_time_ms; ply_ctx.duration = state->full_time; dt_debug (TAG, "UPDATECB CURSTATUS:%x \n", state->cur_status); dt_info(TAG,"CUR TIME %lld S FULL TIME:%lld \n",state->cur_time,state->full_time); return 0; }
int packet_queue_put (dt_packet_queue_t * queue, dt_av_frame_t * frame) { int ret; if (queue->nmutex) return -1; queue->nmutex = 1; if (frame->type == 0 && queue->size >= QUEUE_MAX_VBUF_SIZE) { dt_debug (TAG, "[%s:%d]type:%d(0 video 1 audio) packet queue exceed size\n", __FUNCTION__, __LINE__, frame->type); queue->nmutex = 0; return -2; } if (frame->type == 1 && queue->size >= QUEUE_MAX_ABUF_SIZE) { dt_debug (TAG, "[%s:%d]type:%d(0 video 1 audio) packet queue exceed size\n", __FUNCTION__, __LINE__, frame->type); queue->nmutex = 0; return -2; } ret = packet_queue_put_frame (queue, frame); queue->nmutex = 0; //printf("[%s:%d] packet queue in ok\n",__FUNCTION__,__LINE__); return ret; }
static int stream_file_seek(stream_wrapper_t * wrapper, int64_t pos, int whence) { file_ctx_t *ctx = (file_ctx_t *)wrapper->stream_priv; stream_ctrl_t *info = &wrapper->info; info->eof_flag = 0; if (whence == AVSEEK_SIZE) { dt_debug(TAG, "REQUEST STREAM SIZE:%lld \n", info->stream_size); return info->stream_size; } if (lseek(ctx->fd, pos, whence) < 0) { return -1; } if (whence == SEEK_SET) { info->cur_pos = pos; } if (whence == SEEK_CUR) { info->cur_pos += pos; } return DTERROR_NONE; }
static int stream_ffmpeg_seek (stream_wrapper_t * wrapper, int64_t pos, int whence) { AVIOContext *ctx = (AVIOContext *)wrapper->stream_priv; stream_ctrl_t *info = &wrapper->info; info->eof_flag = 0; if(whence == AVSEEK_SIZE) { dt_debug(TAG,"REQUEST STREAM SIZE:%lld \n",info->stream_size); return info->stream_size; } if (avio_seek(ctx, pos, whence) < 0) { info->eof_flag = 1; return -1; } if(whence == SEEK_SET) info->cur_pos = pos; if(whence == SEEK_CUR) info->cur_pos += pos; return DTERROR_NONE; }
static int64_t ao_alsa_get_latency(dtaudio_output_t *aout) { alsa_ctx_t *ctx = (alsa_ctx_t *)wrapper->ao_priv; unsigned int sample_num; uint64_t latency, latency_s; ctx->buf_level = ctx->buf_size - ao_alsa_space(ctx); sample_num = ctx->buf_level / (wrapper->para.dst_channels * wrapper->para.bps / 8); float pts_ratio = (double) 90000 / wrapper->para.samplerate; latency = (sample_num * pts_ratio); latency_s = latency / 90000; dt_debug(TAG, "[%s:%d]==alsa_level:%d thres:%d sample_num:%d buffersize:%d latency:%llu latency_s:%llu \n", __FUNCTION__, __LINE__, ctx->buf_level, ctx->buf_threshold, sample_num, ctx->buf_size, latency, latency_s); return latency; }
int video_drop (dtvideo_context_t * vctx, int64_t target_pts) { int64_t diff = target_pts - video_get_first_pts (vctx); int diff_time = diff / 90; if (diff_time > AVSYNC_DROP_THRESHOLD) { dt_info (TAG, "diff time exceed %d ms, do not drop!\n", diff_time); return 0; } dt_info (TAG, "[%s:%d]target pts:%lld \n", __FUNCTION__, __LINE__, target_pts); AVPicture_t *pic = NULL; int64_t cur_pts = video_get_first_pts (vctx); int drop_count = 300; do { pic = dtvideo_output_read ((void *) vctx); if (!pic) { if (drop_count-- == 0) { dt_info (TAG, "3s read nothing, quit drop video\n"); break; } usleep (100); continue; } drop_count = 300; cur_pts = pic->pts; dt_debug (TAG, "read pts:%lld \n", pic->pts); free (pic); pic = NULL; if (cur_pts > target_pts) break; } while (1); dt_info (TAG, "video drop finish,drop count:%d \n", drop_count); vctx->current_pts = cur_pts; dtvideo_update_pts ((void *) vctx); return 0; }
static int stream_cache_read (stream_wrapper_t * wrapper,uint8_t *buf,int len) { cache_ctx_t *ctx = (cache_ctx_t *)wrapper->stream_priv; stream_ctrl_t *info = &wrapper->info; stream_cache_t *cache = ctx->cache; int level = cache_level(cache); if(level == 0) return 0; int r = cache_read(cache,buf,len); dt_debug(TAG,"read %d byte \n",r); if(r>0) info->cur_pos += r; if(r<=0 && ctx->cache_flag == ST_FLAG_EOF) { if(ctx->cache_flag == ST_FLAG_EOF) info->eof_flag = 1; else r=0; } return r; }
static int calc_cur_time(dtplayer_context_t * dtp_ctx, host_state_t * host_state) { player_ctrl_t *ctrl_info = &dtp_ctx->ctrl_info; dtp_state_t *play_stat = &dtp_ctx->state; int has_audio = ctrl_info->has_audio; int has_video = ctrl_info->has_video; int64_t apts_first = host_state->pts_audio_first; int64_t vpts_first = host_state->pts_video_first; if (ctrl_info->start_time > 0) { play_stat->start_time = ctrl_info->start_time; dt_info(TAG, "START TIME:0x%llx \n", ctrl_info->start_time); } if (ctrl_info->first_time == -1) { if (has_audio && has_video) { if (PTS_VALID(apts_first) && PTS_VALID(vpts_first)) { if (llabs(apts_first - vpts_first) < FIRST_TIME_DIFF_MAX) { ctrl_info->first_time = (apts_first > vpts_first) ? vpts_first : apts_first; } else { if (llabs(vpts_first - play_stat->start_time) < FIRST_TIME_DIFF_MAX) { ctrl_info->first_time = vpts_first; } else if (llabs(apts_first - play_stat->start_time) < FIRST_TIME_DIFF_MAX) { ctrl_info->first_time = apts_first; } } } else if (PTS_VALID(apts_first)) { ctrl_info->first_time = apts_first; } else if (PTS_VALID(vpts_first)) { ctrl_info->first_time = vpts_first; } } else { ctrl_info->first_time = host_state->sys_time_current; } dt_info(TAG, "[apts_first:0x%llx] [vpts_first:0x%llx] [starttime:0x%llx] -> first_time:0x%llx \n", apts_first, vpts_first, play_stat->start_time, ctrl_info->first_time); } if (play_stat->full_time == 0) { play_stat->full_time = dtp_ctx->media_info->duration; } int64_t sys_time_start = host_state->sys_time_start; int64_t sys_time_current = host_state->sys_time_current; int64_t pts_audio_current = host_state->pts_audio_current; int audio_discontinue_flag = host_state->audio_discontinue_flag; int64_t audio_discontinue_point = host_state->audio_discontinue_point; int64_t pts_video_current = host_state->pts_video_current; int video_discontinue_flag = host_state->video_discontinue_flag; int64_t video_discontinue_point = host_state->video_discontinue_point; int avdiff = llabs(pts_audio_current - pts_video_current) / DT_PTS_FREQ_MS; int64_t sys_time = -1; int64_t start_time = ctrl_info->first_time; int discontinue_flag = 0; if (has_audio && has_video) { if (audio_discontinue_flag && video_discontinue_flag) { // both discontinue occured play_stat->discontinue_point_ms = play_stat->cur_time_ms; if (avdiff < AVSYNC_THRESHOLD_MAX) { player_host_set_info(dtp_ctx, HOST_CMD_SET_DISCONTINUE_FLAG, (unsigned long)(&discontinue_flag)); } sys_time = pts_video_current; if (audio_discontinue_point > 0) { start_time = audio_discontinue_point; } } else if (audio_discontinue_flag) { // only audio discontinue occured if (avdiff < AVSYNC_THRESHOLD_MAX) { player_host_set_info(dtp_ctx, HOST_CMD_SET_DISCONTINUE_FLAG, (unsigned long)(&discontinue_flag)); } sys_time = pts_video_current; if (video_discontinue_point > 0) { start_time = video_discontinue_point; } } else if (video_discontinue_flag) { // only video discontinue occured if (avdiff < AVSYNC_THRESHOLD_MAX) { player_host_set_info(dtp_ctx, HOST_CMD_SET_DISCONTINUE_FLAG, (unsigned long)(&discontinue_flag)); } sys_time = pts_audio_current; if (audio_discontinue_point > 0) { start_time = audio_discontinue_point; } } else { if (PTS_VALID(vpts_first)) { sys_time = pts_video_current; } else { sys_time = pts_audio_current; } if (audio_discontinue_point > 0) { start_time = audio_discontinue_point; } } } else { sys_time = sys_time_current; start_time = sys_time_start; } sys_time += play_stat->discontinue_point_ms * DT_PTS_FREQ_MS; sys_time -= start_time; play_stat->cur_time = sys_time / DT_PTS_FREQ; play_stat->cur_time_ms = sys_time / DT_PTS_FREQ_MS; dt_debug(TAG, "---------------------------------------------\n"); dt_debug(TAG, "apts:%llx audio_discontinue_flag:%d audio_discontinue_point:%llx\n", pts_audio_current, audio_discontinue_flag, audio_discontinue_point); dt_debug(TAG, "vpts:%llx video_discontinue_flag:%d video_discontinue_point:%llx\n", pts_video_current, video_discontinue_flag, video_discontinue_point); dt_debug(TAG, "sys_time:%llx start_time:%llx\n", (sys_time - play_stat->discontinue_point_ms * DT_PTS_FREQ_MS), start_time); dt_debug(TAG, "---------------------------------------------\n"); return 0; }
int demuxer_open(dtdemuxer_context_t * dem_ctx) { int ret = 0; /* open stream */ dtstream_para_t para; para.stream_name = dem_ctx->file_name; ret = dtstream_open(&dem_ctx->stream_priv, ¶, dem_ctx); if (ret != DTERROR_NONE) { dt_error(TAG, "stream open failed \n"); goto DEMUXER_SELECT; } dt_info(TAG, "probe enable start \n"); int probe_enable = dtp_setting.demuxer_probe; int probe_size = dtstream_local(dem_ctx->stream_priv) ? PROBE_LOCAL_SIZE : PROBE_STREAM_SIZE; dt_info(TAG, "probe enable:%d \n", probe_enable); dt_info(TAG, "probe size:%d \n", probe_size); if (probe_enable) { int64_t old_pos = dtstream_tell(dem_ctx->stream_priv); dt_info(TAG, "old:%lld \n", old_pos); ret = buf_init(&dem_ctx->probe_buf, probe_size); if (ret < 0) { return -1; } //buffer data for probe int total = probe_size; int rtotal = 0; int rlen = 0; int retry = 100; const int read_once = 10240; uint8_t tmp_buf[read_once]; do { rlen = dtstream_read(dem_ctx->stream_priv, tmp_buf, read_once); if (rlen < 0) { // read eof if ((probe_size - total) == 0) { return -1; } else { break; } } if (rlen > 0) { retry = 20; } else { usleep(100000); // total time :20 * 100000 = 10s retry--; } if (retry == 0) { dt_info(TAG, "retry 100 times, total:%d \n", total); if ((probe_size - total) == 0) { return -1; } else { break; } } dt_debug(TAG, "total:%d rtotal:%d rlen:%d \n", total, rtotal, rlen); if (rlen == 0) { continue; } if (buf_put(&dem_ctx->probe_buf, tmp_buf, rlen) == 0) { // full break; } rtotal += rlen; total -= rlen; if (total == 0) { break; } } while (1); dt_info(TAG, "buffered %d bytes for probe \n", probe_size - total); ret = dtstream_seek(dem_ctx->stream_priv, old_pos, SEEK_SET); dt_info(TAG, "seek back to:%lld ret:%d \n", old_pos, ret); } DEMUXER_SELECT: /* select demuxer */ if (demuxer_select(dem_ctx) == -1) { dt_error(TAG, "select demuxer failed \n"); return -1; } demuxer_wrapper_t *wrapper = dem_ctx->demuxer; wrapper->parent = dem_ctx; ret = wrapper->open(wrapper); if (ret < 0) { dt_error(TAG, "demuxer open failed\n"); return -1; } dt_info(TAG, "demuxer open ok\n"); dtp_media_info_t *info = &(dem_ctx->media_info); wrapper->setup_info(wrapper, info); dump_media_info(info); dt_info(TAG, "demuxer setup info ok\n"); return 0; }
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; }
/*********************************************************************** ** ** capability check ** ***********************************************************************/ static int opengl_vf_capable(vf_cap_t cap) { int opengl_cap = VF_CAP_COLORSPACE_CONVERT | VF_CAP_CLIP; dt_debug(TAG, "request cap: %x , %s support:%x \n", cap, "opengl vf", ffmpeg_cap); return cap & ffmpeg_cap; }
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 *cache_thread (cache_ctx_t * ctx) { stream_wrapper_t *real_st = ctx->wrapper; stream_cache_t *cache = ctx->cache; uint8_t tmp_buf[READ_PER_TIME]; int rlen = 0; int wlen = 0; do { usleep (10000); if(ctx->cache_flag == ST_FLAG_PAUSE) ctx->cache_status = ST_STATUS_PAUSED; if(ctx->cache_status == ST_STATUS_IDLE) { usleep(100000); continue; } if(ctx->cache_status == ST_STATUS_QUIT) goto QUIT; if(ctx->cache_status == ST_STATUS_PAUSED) // means clean everything { rlen = 0; ctx->cache_flag = ST_FLAG_NULL; ctx->cache_status = ST_STATUS_IDLE; dt_info(TAG,"paused thread, reset rlen and cache\n"); continue; } if(rlen == 0) { rlen = real_st->read(real_st,tmp_buf,READ_PER_TIME); if(rlen < 0) { rlen = 0; ctx->cache_flag = ST_FLAG_EOF; // eof will enter IDLE MODE ctx->cache_status = ST_STATUS_IDLE; dt_info(TAG,"read eof, poll thread enter idle\n"); continue; } dt_debug(TAG, "read ok size:%d \n",rlen); } if(cache_space(cache) < rlen) { usleep(100000); continue; } wlen = cache_write(cache,tmp_buf,rlen); if (wlen == 0) continue; rlen -= wlen; if(rlen > 0) // here some err occured, skip this packet { rlen = 0; continue; } } while (1); QUIT: dt_info (TAG, "cache thread quit ok\n"); pthread_exit (NULL); return 0; }
static void *audio_output_thread(void *args) { dtaudio_output_t *ao = (dtaudio_output_t *) args; ao_wrapper_t *wrapper = ao->wrapper; int rlen, ret, wlen; rlen = ret = wlen = 0; dtaudio_para_t *para = &ao->para; int bytes_per_sample = para->data_width * para->dst_channels / 8; int unit_size = PCM_WRITE_SIZE * para->dst_samplerate * bytes_per_sample / 1000; unit_size = unit_size - unit_size % (4 * bytes_per_sample); uint8_t *buffer = malloc(unit_size); if (!buffer) { // err goto EXIT; } dt_info(TAG, "write :%d ms :%d bytes one time \n", PCM_WRITE_SIZE, unit_size); for (;;) { if (ao->status == AO_STATUS_EXIT) { goto EXIT; } if (ao->status == AO_STATUS_IDLE || ao->status == AO_STATUS_PAUSE) { usleep(100); continue; } /* update audio pts */ audio_update_pts(ao->parent); /*read data from filter or decode buffer */ if (rlen <= 0) { rlen = audio_output_read(ao->parent, buffer, unit_size); if (rlen <= 0) { dt_debug(LOG_TAG, "pcm read failed! \n"); usleep(1000); continue; } #ifdef DTAUDIO_DUMP_PCM FILE *fp = fopen("pcm.out", "ab+"); int flen = 0; if (fp) { flen = fwrite(buffer, 1, rlen, fp); if (flen <= 0) { dt_info(LOG_TAG, "pcm dump failed! \n"); } fclose(fp); } else { dt_error(TAG, "pcm out open failed! \n"); } #endif } /*write to ao device */ wlen = wrapper->write(wrapper, buffer, rlen); if (wlen <= 0) { usleep(1000); continue; } rlen -= wlen; if (rlen > 0) { memmove(buffer, buffer + wlen, rlen); } wlen = 0; } EXIT: dt_info(LOG_TAG, "[file:%s][%s:%d]ao playback thread exit\n", __FILE__, __FUNCTION__, __LINE__); if (buffer) { free(buffer); } buffer = NULL; pthread_exit(NULL); return NULL; }