diff --git a/libeplayer3/container/container_ffmpeg.c b/libeplayer3/container/container_ffmpeg.c index 4eadd19..2cdf789 100644 --- a/libeplayer3/container/container_ffmpeg.c +++ b/libeplayer3/container/container_ffmpeg.c @@ -194,10 +194,10 @@ static char *Codec2Encoding(AVCodecContext * codec, int *version) return NULL; } -long long int calcPts(AVStream * stream, int64_t pts) +int64_t calcPts(AVFormatContext *avfc, AVStream * stream, int64_t pts) { - if (!stream) { - ffmpeg_err("stream / packet null\n"); + if (!avfc || !stream) { + ffmpeg_err("context / stream null\n"); return INVALID_PTS_VALUE; } @@ -206,7 +206,7 @@ long long int calcPts(AVStream * stream, int64_t pts) else if (avContext->start_time == AV_NOPTS_VALUE) pts = 90000.0 * (double) pts * av_q2d(stream->time_base); else - pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avContext->start_time / AV_TIME_BASE; + pts = 90000.0 * (double) pts * av_q2d(stream->time_base) - 90000.0 * avfc->start_time / AV_TIME_BASE; if (pts & 0x8000000000000000ull) pts = INVALID_PTS_VALUE; @@ -234,16 +234,7 @@ static void FFMPEGThread(Context_t * context) hasPlayThreadStarted = 1; - int64_t currentVideoPts = -1, currentAudioPts = -1, showtime = 0, bofcount = 0; - AudioVideoOut_t avOut; - - SwrContext *swr = NULL; - AVFrame *decoded_frame = NULL; - int out_sample_rate = 44100; - int out_channels = 2; - uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO; - int restart_audio_resampling = 0; - + int64_t currentVideoPts = 0, currentAudioPts = 0, showtime = 0, bofcount = 0; ffmpeg_printf(10, "\n"); while (context->playback->isCreationPhase) { @@ -253,6 +244,9 @@ static void FFMPEGThread(Context_t * context) ffmpeg_printf(10, "Running!\n"); while (context && context->playback && context->playback->isPlaying && !context->playback->abortRequested) { + AudioVideoOut_t avOut; + avOut.restart_audio_resampling = 0; + //IF MOVIE IS PAUSED, WAIT if (context->playback->isPaused) { @@ -321,7 +315,7 @@ static void FFMPEGThread(Context_t * context) if (res < 0 && context->playback->BackWard) bofcount = 1; seek_target = INT64_MIN; - restart_audio_resampling = 1; + avOut.restart_audio_resampling = 1; // flush streams unsigned int i; @@ -370,13 +364,14 @@ static void FFMPEGThread(Context_t * context) ffmpeg_printf(200, "packet_size %d - index %d\n", packet_size, pid); if (videoTrack && (videoTrack->Id == pid)) { - currentVideoPts = videoTrack->pts = pts = calcPts(videoTrack->stream, packet.pts); + currentVideoPts = /* CHECK videoTrack->pts = */pts = calcPts(avContext, videoTrack->stream, packet.pts); ffmpeg_printf(200, "VideoTrack index = %d %lld\n", pid, currentVideoPts); avOut.data = packet_data; avOut.len = packet_size; avOut.pts = pts; + avOut.packet = &packet; avOut.type = "video"; avOut.stream = videoTrack->stream; @@ -386,8 +381,9 @@ static void FFMPEGThread(Context_t * context) ffmpeg_err("writing data to video device failed\n"); } } else if (audioTrack && (audioTrack->Id == pid)) { + context->currentAudioPtsP = ¤tAudioPts; //FIXME, temporary workaround only if (!context->playback->BackWard) { - currentAudioPts = audioTrack->pts = pts = calcPts(audioTrack->stream, packet.pts); + currentAudioPts = /* CHECK audioTrack->pts = */pts = calcPts(avContext, audioTrack->stream, packet.pts); ffmpeg_printf(200, "AudioTrack index = %d\n", pid); if (audioTrack->inject_raw_pcm == 1) { @@ -401,137 +397,18 @@ static void FFMPEGThread(Context_t * context) avOut.data = packet_data; avOut.len = packet_size; avOut.pts = pts; + avOut.packet = &packet; avOut.type = "audio"; avOut.stream = audioTrack->stream; avOut.avfc = avContext; if (context->output->audio->Write(context, &avOut) < 0) ffmpeg_err("(raw pcm) writing data to audio device failed\n"); - } else if (audioTrack->inject_as_pcm == 1) { - AVCodecContext *c = ((AVStream *) (audioTrack->stream))->codec; - - if (restart_audio_resampling) { - restart_audio_resampling = 0; - if (swr) { - swr_free(&swr); - swr = NULL; - } - if (decoded_frame) { - av_frame_free(&decoded_frame); - decoded_frame = NULL; - } - context->output->Command(context, OUTPUT_CLEAR, NULL); - context->output->Command(context, OUTPUT_PLAY, NULL); - - AVCodec *codec = avcodec_find_decoder(c->codec_id); - - if (!codec || avcodec_open2(c, codec, NULL)) - fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__); - } - - while (packet_size > 0) { - int got_frame = 0; - if (!decoded_frame) { - if (!(decoded_frame = av_frame_alloc())) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - } else - av_frame_unref(decoded_frame); - - int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &packet); - if (len < 0) { - restart_audio_resampling = 1; - break; - } - - packet_data += len; - packet_size -= len; - - if (!got_frame) - continue; - - int e; - if (!swr) { - int rates[] = { 48000, 96000, 192000, 44100, 88200, 176400, 0 }; - int *rate = rates; - int in_rate = c->sample_rate; - while (*rate && ((*rate / in_rate) * in_rate != *rate) - && (in_rate / *rate) * *rate != in_rate) - rate++; - out_sample_rate = *rate ? *rate : 44100; - swr = swr_alloc(); - out_channels = c->channels; - if (c->channel_layout == 0) { - // FIXME -- need to guess, looks pretty much like a bug in the FFMPEG WMA decoder - c->channel_layout = AV_CH_LAYOUT_STEREO; - } - - out_channel_layout = c->channel_layout; - // player2 won't play mono - if (out_channel_layout == AV_CH_LAYOUT_MONO) { - out_channel_layout = AV_CH_LAYOUT_STEREO; - out_channels = 2; - } - - av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0); - av_opt_set_int(swr, "out_channel_layout", out_channel_layout, 0); - av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0); - av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); - av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0); - av_opt_set_int(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); - - e = swr_init(swr); - if (e < 0) { - fprintf(stderr, - "swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n", - -e, (int) c->channel_layout, - (int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16); - swr_free(&swr); - swr = NULL; - } - } - - uint8_t *output = NULL; - int in_samples = decoded_frame->nb_samples; - int out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP); - e = av_samples_alloc(&output, NULL, out_channels, out_samples, AV_SAMPLE_FMT_S16, 1); - if (e < 0) { - fprintf(stderr, "av_samples_alloc: %d\n", -e); - continue; - } - // FIXME. PTS calculation is probably broken. - int64_t next_in_pts = av_rescale(av_frame_get_best_effort_timestamp(decoded_frame), - ((AVStream *) audioTrack->stream)->time_base.num * (int64_t) out_sample_rate * c->sample_rate, - ((AVStream *) audioTrack->stream)->time_base.den); - int64_t next_out_pts = av_rescale(swr_next_pts(swr, next_in_pts), - ((AVStream *) audioTrack->stream)->time_base.den, - ((AVStream *) audioTrack->stream)->time_base.num * (int64_t) out_sample_rate * c->sample_rate); - currentAudioPts = audioTrack->pts = pts = calcPts(audioTrack->stream, next_out_pts); - out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **) - &decoded_frame->data[0], in_samples); - - avOut.uSampleRate = out_sample_rate; - avOut.uNoOfChannels = av_get_channel_layout_nb_channels(out_channel_layout); - avOut.uBitsPerSample = 16; - avOut.bLittleEndian = 1; - - avOut.data = output; - avOut.len = out_samples * sizeof(short) * out_channels; - - avOut.pts = videoTrack ? pts : 0; - avOut.type = "audio"; - avOut.stream = audioTrack->stream; - avOut.avfc = avContext; - - if (context->output->audio->Write(context, &avOut) < 0) - ffmpeg_err("writing data to audio device failed\n"); - av_freep(&output); - } } else { avOut.data = packet_data; avOut.len = packet_size; avOut.pts = pts; + avOut.packet = &packet; avOut.type = "audio"; avOut.stream = audioTrack->stream; avOut.avfc = avContext; @@ -544,7 +421,7 @@ static void FFMPEGThread(Context_t * context) float duration = 3.0; ffmpeg_printf(100, "subtitleTrack->stream %p \n", subtitleTrack->stream); - pts = calcPts(subtitleTrack->stream, packet.pts); + pts = calcPts(avContext, subtitleTrack->stream, packet.pts); if (duration > 0.0) { /* is there a decoder ? */ @@ -586,11 +463,6 @@ static void FFMPEGThread(Context_t * context) dvbsub_ass_clear(); - if (swr) - swr_free(&swr); - if (decoded_frame) - av_frame_free(&decoded_frame); - if (context->playback) context->playback->abortPlayback = 1; hasPlayThreadStarted = 0; @@ -903,11 +775,6 @@ int container_ffmpeg_update_tracks(Context_t * context, char *filename) track.duration = (double) stream->duration * av_q2d(stream->time_base) * 1000.0; } - if (!strncmp(encoding, "A_IPCM", 6)) { - track.inject_as_pcm = 1; - ffmpeg_printf(10, " Handle inject_as_pcm = %d\n", track.inject_as_pcm); - } - if (context->manager->audio) { if (context->manager->audio->Command(context, MANAGER_ADD, &track) < 0) { /* konfetti: fixme: is this a reason to return with error? */ diff --git a/libeplayer3/include/common.h b/libeplayer3/include/common.h index 9e62b02..57da81a 100644 --- a/libeplayer3/include/common.h +++ b/libeplayer3/include/common.h @@ -6,12 +6,14 @@ #include "manager.h" #include "playback.h" #include +#include typedef struct Context_s { PlaybackHandler_t *playback; ContainerHandler_t *container; OutputHandler_t *output; ManagerHandler_t *manager; + int64_t *currentAudioPtsP; } Context_t; int container_ffmpeg_update_tracks(Context_t * context, char *filename); diff --git a/libeplayer3/include/manager.h b/libeplayer3/include/manager.h index 8a8c543..afe5d63 100644 --- a/libeplayer3/include/manager.h +++ b/libeplayer3/include/manager.h @@ -38,8 +38,8 @@ typedef struct Track_s { char *language; /* length of track */ - uint64_t duration; - uint64_t pts; + int64_t duration; +//CHECK int64_t pts; /* context from ffmpeg */ AVFormatContext *avfc; @@ -53,7 +53,6 @@ typedef struct Track_s { /* If player2 or the elf do not support decoding of audio codec set this. * AVCodec is than used for softdecoding and stream will be injected as PCM */ - int inject_as_pcm; int inject_raw_pcm; int pending; diff --git a/libeplayer3/include/output.h b/libeplayer3/include/output.h index 2e9f459..0cdeb53 100644 --- a/libeplayer3/include/output.h +++ b/libeplayer3/include/output.h @@ -42,15 +42,15 @@ typedef struct { int uSampleRate; int uBitsPerSample; int bLittleEndian; + int restart_audio_resampling; - uint64_t pts; + int64_t pts; char *type; - /* context from ffmpeg */ AVFormatContext *avfc; - /* stream from ffmpeg */ AVStream *stream; + AVPacket *packet; } AudioVideoOut_t; struct Context_s; diff --git a/libeplayer3/include/writer.h b/libeplayer3/include/writer.h index 9a0c10d..ac37738 100644 --- a/libeplayer3/include/writer.h +++ b/libeplayer3/include/writer.h @@ -12,19 +12,23 @@ typedef enum { eNone, eAudio, eVideo, eGfx } eWriterType_t; +struct Context_s; +typedef struct Context_s Context_t; + typedef struct { int fd; uint8_t *data; unsigned int len; - uint64_t Pts; + int64_t Pts; int uNoOfChannels; int uSampleRate; int uBitsPerSample; int bLittleEndian; - /* context from ffmpeg */ + int restart_audio_resampling; AVFormatContext *avfc; - /* stream from ffmpeg */ AVStream *stream; + AVPacket *packet; + Context_t *context; } WriterAVCallData_t; typedef struct WriterCaps_s { diff --git a/libeplayer3/output/linuxdvb.c b/libeplayer3/output/linuxdvb.c index aa29508..bb16b83 100644 --- a/libeplayer3/output/linuxdvb.c +++ b/libeplayer3/output/linuxdvb.c @@ -940,6 +940,7 @@ static int Write(Context_t *context, AudioVideoOut_t *out) call.data = out->data; call.len = out->len; call.Pts = out->pts; + call.packet = out->packet; if (writer->writeData) res = writer->writeData(&call); @@ -977,12 +978,14 @@ static int Write(Context_t *context, AudioVideoOut_t *out) call.data = out->data; call.len = out->len; call.Pts = out->pts; + call.packet = out->packet; call.uNoOfChannels = out->uNoOfChannels; call.uSampleRate = out->uSampleRate; call.uBitsPerSample = out->uBitsPerSample; call.bLittleEndian = out->bLittleEndian; - + call.restart_audio_resampling = out->restart_audio_resampling; + call.context = context; if (writer->writeData) res = writer->writeData(&call); diff --git a/libeplayer3/output/writer/pcm.c b/libeplayer3/output/writer/pcm.c index 6bcb63f..84a9f9b 100644 --- a/libeplayer3/output/writer/pcm.c +++ b/libeplayer3/output/writer/pcm.c @@ -289,34 +289,187 @@ static int writeData(WriterAVCallData_t *call) return size; } + +SwrContext *swr = NULL; +AVFrame *decoded_frame = NULL; +int out_sample_rate = 44100; +int out_channels = 2; +uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO; +int restart_audio_resampling = 0; + +static int resetIpcm() +{ + if (swr) + swr_free(&swr); + if (decoded_frame) + av_frame_free(&decoded_frame); + + return 0; +} + +int64_t calcPts(AVFormatContext *, AVStream *, int64_t); + +static int writeDataIpcm(WriterAVCallData_t *call) +{ + AVCodecContext *c = call->stream->codec; + AVPacket *packet = call->packet; + uint8_t *packet_data = packet->data; + unsigned int packet_size = packet->size; + + if (call->restart_audio_resampling) + call->restart_audio_resampling = 1; + + if (restart_audio_resampling) { + restart_audio_resampling = 0; + if (swr) { + swr_free(&swr); + swr = NULL; + } + if (decoded_frame) { + av_frame_free(&decoded_frame); + decoded_frame = NULL; + } + call->context->output->Command(call->context, OUTPUT_CLEAR, NULL); + call->context->output->Command(call->context, OUTPUT_PLAY, NULL); + + AVCodec *codec = avcodec_find_decoder(c->codec_id); + + if (!codec || avcodec_open2(c, codec, NULL)) + fprintf(stderr, "%s %d: avcodec_open2 failed\n", __func__, __LINE__); + } + + while (packet_size > 0) { + int got_frame = 0; + if (!decoded_frame) { + if (!(decoded_frame = av_frame_alloc())) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + } else + av_frame_unref(decoded_frame); + + int len = avcodec_decode_audio4(c, decoded_frame, &got_frame, packet); + if (len < 0) { + restart_audio_resampling = 1; + break; + } + + packet_data += len; + packet_size -= len; + + if (!got_frame) + continue; + + int e; + if (!swr) { + int rates[] = { 48000, 96000, 192000, 44100, 88200, 176400, 0 }; + int *rate = rates; + int in_rate = c->sample_rate; + while (*rate && ((*rate / in_rate) * in_rate != *rate) && (in_rate / *rate) * *rate != in_rate) + rate++; + out_sample_rate = *rate ? *rate : 44100; + swr = swr_alloc(); + out_channels = c->channels; + if (c->channel_layout == 0) { + // FIXME -- need to guess, looks pretty much like a bug in the FFMPEG WMA decoder + c->channel_layout = AV_CH_LAYOUT_STEREO; + } + + out_channel_layout = c->channel_layout; + // player2 won't play mono + if (out_channel_layout == AV_CH_LAYOUT_MONO) { + out_channel_layout = AV_CH_LAYOUT_STEREO; + out_channels = 2; + } + + av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0); + av_opt_set_int(swr, "out_channel_layout", out_channel_layout, 0); + av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0); + av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0); + av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0); + av_opt_set_int(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + + e = swr_init(swr); + if (e < 0) { + fprintf(stderr, + "swr_init: %d (icl=%d ocl=%d isr=%d osr=%d isf=%d osf=%d\n", + -e, (int) c->channel_layout, + (int) out_channel_layout, c->sample_rate, out_sample_rate, c->sample_fmt, AV_SAMPLE_FMT_S16); + swr_free(&swr); + swr = NULL; + } + } + + uint8_t *output = NULL; + int in_samples = decoded_frame->nb_samples; + int out_samples = av_rescale_rnd(swr_get_delay(swr, c->sample_rate) + in_samples, out_sample_rate, c->sample_rate, AV_ROUND_UP); + e = av_samples_alloc(&output, NULL, out_channels, out_samples, AV_SAMPLE_FMT_S16, 1); + if (e < 0) { + fprintf(stderr, "av_samples_alloc: %d\n", -e); + continue; + } + // FIXME. PTS calculation is probably broken. + int64_t pts; + int64_t next_in_pts = av_rescale(av_frame_get_best_effort_timestamp(decoded_frame), + call->stream->time_base.num * (int64_t) out_sample_rate * c->sample_rate, + call->stream->time_base.den); + int64_t next_out_pts = av_rescale(swr_next_pts(swr, next_in_pts), + call->stream->time_base.den, + call->stream->time_base.num * (int64_t) out_sample_rate * c->sample_rate); + *(call->context->currentAudioPtsP) = /* audioTrack->pts = */ pts = calcPts(call->avfc, call->stream, next_out_pts); + out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **) + &decoded_frame->data[0], in_samples); + + WriterAVCallData_t pcmOut; + pcmOut.fd = call->fd; + pcmOut.uSampleRate = out_sample_rate; + pcmOut.uNoOfChannels = av_get_channel_layout_nb_channels(out_channel_layout); + pcmOut.uBitsPerSample = 16; + pcmOut.bLittleEndian = 1; + + pcmOut.data = output; + pcmOut.len = out_samples * sizeof(short) * out_channels; + + pcmOut.Pts = pts; // FIXME videoTrack ? pts : 0; + pcmOut.stream = call->stream; + pcmOut.avfc = call->avfc; + pcmOut.packet = NULL; + + writeData(&pcmOut); + + av_freep(&output); + } + return packet->size; +} + /* ***************************** */ /* Writer Definition */ /* ***************************** */ static WriterCaps_t caps_pcm = { - "pcm", - eAudio, - "A_PCM", - AUDIO_ENCODING_LPCMA + "pcm", + eAudio, + "A_PCM", + AUDIO_ENCODING_LPCMA }; struct Writer_s WriterAudioPCM = { - &reset, - &writeData, - NULL, - &caps_pcm + &reset, + &writeData, + NULL, + &caps_pcm }; static WriterCaps_t caps_ipcm = { - "ipcm", - eAudio, - "A_IPCM", - AUDIO_ENCODING_LPCMA + "ipcm", + eAudio, + "A_IPCM", + AUDIO_ENCODING_LPCMA }; struct Writer_s WriterAudioIPCM = { - &reset, - &writeData, - NULL, - &caps_ipcm + &resetIpcm, + &writeDataIpcm, + NULL, + &caps_ipcm };