int player_prepare(State **ps, int from_thread) { int audio_index = -1; int video_index = -1; int i; State *state = *ps; if (state && state->pFormatCtx) { avformat_close_input(&state->pFormatCtx); } state->pFormatCtx = NULL; state->audio_stream = -1; state->video_stream = -1; state->audio_st = NULL; state->video_st = NULL; printf("Path: %s\n", state->filename); AVDictionary *options = NULL; av_dict_set(&options, "user-agent", "FFmpegMediaPlayer", 0); if (avformat_open_input(&state->pFormatCtx, state->filename, NULL, &options) != 0) { printf("Input file could not be opened\n"); *ps = NULL; return FAILURE; } if (avformat_find_stream_info(state->pFormatCtx, NULL) < 0) { printf("Stream information could not be retrieved\n"); avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } char duration[30] = "0"; get_duration(state->pFormatCtx, duration); av_dict_set(&state->pFormatCtx->metadata, DURATION, duration, 0); // Find the first audio and video stream for (i = 0; i < state->pFormatCtx->nb_streams; i++) { if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index = i; } if (state->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index = i; } set_codec(state->pFormatCtx, i); } if (audio_index >= 0) { stream_component_open(state, audio_index, from_thread); } if (video_index >= 0) { stream_component_open(state, video_index, from_thread); } if (state->video_stream < 0 && state->audio_stream < 0) { avformat_close_input(&state->pFormatCtx); *ps = NULL; return FAILURE; } state->pFormatCtx->interrupt_callback.callback = decode_interrupt_cb; state->pFormatCtx->interrupt_callback.opaque = state; // fill the inital buffer AVPacket packet; memset(&packet, 0, sizeof(packet)); //make sure we can safely free it int j, ret; int bytes_written = 0; while (bytes_written < state->buffer_size) { for (j = 0; j < state->pFormatCtx->nb_streams; j++) { //av_init_packet(&packet); ret = av_read_frame(state->pFormatCtx, &packet); if (ret < 0) { if (ret == AVERROR_EOF || url_feof(state->pFormatCtx->pb)) { //break; } } int frame_size_ptr = 0; ret = decode_frame_from_packet(state, &packet, &frame_size_ptr, from_thread); __android_log_print(ANDROID_LOG_ERROR, "TAG", "Fill buffer: %d -> %d", frame_size_ptr, state->buffer_size); bytes_written = bytes_written + frame_size_ptr; av_free_packet(&packet); } } *ps = state; state->notify_callback(state->clazz, MEDIA_PREPARED, 0, 0, from_thread); return SUCCESS; }
int audio_decode_frame(VideoState *is, double *pts_ptr) { int len1, data_size = 0, n; AVPacket *pkt = &is->audio_pkt; double pts; for(;;) { while(is->audio_pkt_size > 0) { int got_frame = 0; len1 = avcodec_decode_audio4(is->audio_st->codec, &is->audio_frame, &got_frame, pkt); if(len1 < 0) { /* if error, skip frame */ is->audio_pkt_size = 0; break; } if (got_frame) { if (is->audio_frame.format != AV_SAMPLE_FMT_S16) { data_size = decode_frame_from_packet(is, is->audio_frame); } else { data_size = av_samples_get_buffer_size ( NULL, is->audio_st->codec->channels, is->audio_frame.nb_samples, is->audio_st->codec->sample_fmt, 1 ); memcpy(is->audio_buf, is->audio_frame.data[0], data_size); } } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if(data_size <= 0) { /* No data yet, get more frames */ continue; } pts = is->audio_clock; *pts_ptr = pts; n = 2 * is->audio_st->codec->channels; is->audio_clock += (double)data_size / (double)(n * is->audio_st->codec->sample_rate); /* We have data, return it and come back for more later */ return data_size; } if(pkt->data) av_free_packet(pkt); if(is->quit) { return -1; } /* next packet */ if(packet_queue_get(is, &is->audioq, pkt, 1) < 0) { return -1; } if(pkt->data == is->flush_pkt.data) { avcodec_flush_buffers(is->audio_st->codec); continue; } is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ if(pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } }
void player_decode(void *data) { State *state = (State *) data; int ret; int eof = 0; for (;;) { if (state->abort_request) { break; } if (state->paused != state->last_paused) { state->last_paused = state->paused; if (state->paused) { state->read_pause_return = av_read_pause(state->pFormatCtx); } else { av_read_play(state->pFormatCtx); } } if (state->seek_req) { int64_t seek_target = state->seek_pos; int64_t seek_min = state->seek_rel > 0 ? seek_target - state->seek_rel + 2: INT64_MIN; int64_t seek_max = state->seek_rel < 0 ? seek_target - state->seek_rel - 2: INT64_MAX; ret = avformat_seek_file(state->pFormatCtx, -1, seek_min, seek_target, seek_max, state->seek_flags); if (ret < 0) { fprintf(stderr, "%s: error while seeking\n", state->pFormatCtx->filename); } else { if (state->audio_stream >= 0) { avcodec_flush_buffers(state->audio_st->codec); } state->notify_callback(state->clazz, MEDIA_SEEK_COMPLETE, 0, 0, FROM_THREAD); } state->seek_req = 0; eof = 0; } if (state->paused) { goto sleep; } AVPacket packet; memset(&packet, 0, sizeof(packet)); //make sure we can safely free it int i; for (i = 0; i < state->pFormatCtx->nb_streams; ++i) { //av_init_packet(&packet); ret = av_read_frame(state->pFormatCtx, &packet); if (ret < 0) { if (ret == AVERROR_EOF || url_feof(state->pFormatCtx->pb)) { eof = 1; break; } } int frame_size_ptr; ret = decode_frame_from_packet(state, &packet, &frame_size_ptr, FROM_THREAD); av_free_packet(&packet); if (ret != 0) { //an error or a frame decoded // TODO add this bacl=k } } if (eof) { break; } sleep: usleep(100); } if (eof) { state->notify_callback(state->clazz, MEDIA_PLAYBACK_COMPLETE, 0, 0, FROM_THREAD); } }