diff --git a/Output/x64/acinerella.dll b/Output/x64/acinerella.dll index 06abee8d..e851fd01 100644 Binary files a/Output/x64/acinerella.dll and b/Output/x64/acinerella.dll differ diff --git a/Output/x64/avcodec-54.dll b/Output/x64/avcodec-54.dll index b677a13a..ca074e7c 100644 Binary files a/Output/x64/avcodec-54.dll and b/Output/x64/avcodec-54.dll differ diff --git a/Output/x64/avformat-54.dll b/Output/x64/avformat-54.dll index 115949e2..40521b17 100644 Binary files a/Output/x64/avformat-54.dll and b/Output/x64/avformat-54.dll differ diff --git a/Output/x64/avutil-51.dll b/Output/x64/avutil-51.dll new file mode 100644 index 00000000..5f8cdf7d Binary files /dev/null and b/Output/x64/avutil-51.dll differ diff --git a/Output/x64/avutil-52.dll b/Output/x64/avutil-52.dll index d8aa1179..d1985df4 100644 Binary files a/Output/x64/avutil-52.dll and b/Output/x64/avutil-52.dll differ diff --git a/Output/x64/swresample-0.dll b/Output/x64/swresample-0.dll index ad600fdb..f1150429 100644 Binary files a/Output/x64/swresample-0.dll and b/Output/x64/swresample-0.dll differ diff --git a/Output/x64/swscale-2.dll b/Output/x64/swscale-2.dll index 58cf9119..dcc41fd3 100644 Binary files a/Output/x64/swscale-2.dll and b/Output/x64/swscale-2.dll differ diff --git a/Output/x86/acinerella.dll b/Output/x86/acinerella.dll index e83b3f64..a39e3501 100644 Binary files a/Output/x86/acinerella.dll and b/Output/x86/acinerella.dll differ diff --git a/Output/x86/avcodec-54.dll b/Output/x86/avcodec-54.dll index 62616e37..97d7f850 100644 Binary files a/Output/x86/avcodec-54.dll and b/Output/x86/avcodec-54.dll differ diff --git a/Output/x86/avformat-54.dll b/Output/x86/avformat-54.dll index 68d8c5d4..7328c561 100644 Binary files a/Output/x86/avformat-54.dll and b/Output/x86/avformat-54.dll differ diff --git a/Output/x86/avutil-51.dll b/Output/x86/avutil-51.dll new file mode 100644 index 00000000..5ab61687 Binary files /dev/null and b/Output/x86/avutil-51.dll differ diff --git a/Output/x86/avutil-52.dll b/Output/x86/avutil-52.dll index 12ab8847..af2ce47e 100644 Binary files a/Output/x86/avutil-52.dll and b/Output/x86/avutil-52.dll differ diff --git a/Output/x86/swresample-0.dll b/Output/x86/swresample-0.dll index 2b52c0f4..060469a0 100644 Binary files a/Output/x86/swresample-0.dll and b/Output/x86/swresample-0.dll differ diff --git a/Output/x86/swscale-2.dll b/Output/x86/swscale-2.dll index e7b7dd3d..afa902a0 100644 Binary files a/Output/x86/swscale-2.dll and b/Output/x86/swscale-2.dll differ diff --git a/Vocaluxe/Lib/Sound/Decoder/CAudioDecoderFFmpeg.cs b/Vocaluxe/Lib/Sound/Decoder/CAudioDecoderFFmpeg.cs index 68e7bd9f..e7315aa4 100644 --- a/Vocaluxe/Lib/Sound/Decoder/CAudioDecoderFFmpeg.cs +++ b/Vocaluxe/Lib/Sound/Decoder/CAudioDecoderFFmpeg.cs @@ -11,6 +11,10 @@ namespace Vocaluxe.Lib.Sound.Decoder { class CAudioDecoderFFmpeg: CAudioDecoder { + private TAc_read_callback _rc; + private TAc_seek_callback _sc; + private FileStream _fs; + private IntPtr _instance = IntPtr.Zero; private IntPtr _audiodecoder = IntPtr.Zero; @@ -23,7 +27,11 @@ namespace Vocaluxe.Lib.Sound.Decoder public override void Init() { + _rc = new TAc_read_callback(read_proc); + _sc = new TAc_seek_callback(seek_proc); + _FileOpened = false; + _Initialized = true; } @@ -33,49 +41,63 @@ namespace Vocaluxe.Lib.Sound.Decoder return; _FileName = FileName; - _instance = CAcinerella.ac_init(); + _fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read); - int ret = 0; - if ((ret = CAcinerella.ac_open2(_instance, _FileName)) < 0) - { - CLog.LogError("Error opening sound file (Errorcode: " + ret.ToString() + "): " + _FileName); - return; - } + _instance = CAcinerella.ac_init(); + CAcinerella.ac_open(_instance, IntPtr.Zero, null, _rc, _sc, null, IntPtr.Zero); _Instance = (TAc_instance)Marshal.PtrToStructure(_instance, typeof(TAc_instance)); - if (!_Instance.opened || _Instance.info.duration == 0) + if (!_Instance.opened) { - if (!_Instance.opened) - CLog.LogError("Can't open sound file: " + _FileName); - else - CLog.LogError("Can't open sound file (length = 0?): " + _FileName); + //Free(); return; } - try + int AudioStreamIndex = -1; + + TAc_stream_info Info = new TAc_stream_info(); + for (int i = 0; i < _Instance.stream_count; i++) { - _audiodecoder = CAcinerella.ac_create_audio_decoder(_instance); - } - catch (Exception e) - { - CLog.LogError("Can't create audio decoder for file: " + _FileName + "; " + e.Message); - return; + CAcinerella.ac_get_stream_info(_instance, i, out Info); + + if (Info.stream_type == TAc_stream_type.AC_STREAM_TYPE_AUDIO) + { + try + { + _audiodecoder = CAcinerella.ac_create_decoder(_instance, i); + } + catch (Exception) + { + return; + } + + AudioStreamIndex = i; + break; + } } - if (_audiodecoder == IntPtr.Zero) + if (AudioStreamIndex < 0) { - CLog.LogError("Can't create audio decoder for file: " + _FileName); + //Free(); return; } TAc_decoder Audiodecoder = (TAc_decoder)Marshal.PtrToStructure(_audiodecoder, typeof(TAc_decoder)); + _FormatInfo = new FormatInfo(); + _FormatInfo.SamplesPerSecond = Audiodecoder.stream_info.audio_info.samples_per_second; _FormatInfo.BitDepth = Audiodecoder.stream_info.audio_info.bit_depth; _FormatInfo.ChannelCount = Audiodecoder.stream_info.audio_info.channel_count; _CurrentTime = 0f; + + if (_FormatInfo.BitDepth != 16) + { + CLog.LogError("Unsupported BitDepth in file " + FileName); + return; + } _FileOpened = true; } @@ -179,5 +201,23 @@ namespace Vocaluxe.Lib.Sound.Decoder Buffer = null; TimeStamp = 0f; } + + #region Callbacks + private Int32 read_proc(IntPtr sender, IntPtr buf, Int32 size) + { + Int32 r = 0; + + byte[] bb = new byte[size]; + r = _fs.Read(bb, 0, size); + Marshal.Copy(bb, 0, buf, size); + + return r; + } + + private Int64 seek_proc(IntPtr sender, Int64 pos, Int32 whence) + { + return (Int64)_fs.Seek((long)pos, (SeekOrigin)whence); + } + #endregion Callbacks } } diff --git a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs index 54d90fe3..0b3fbc90 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs @@ -253,17 +253,6 @@ namespace Vocaluxe.Lib.Video.Acinerella return _ac_open(PAc_instance, sender, open_proc, read_proc, seek_proc, close_proc, proberesult); } } - - [DllImport(AcDll, EntryPoint = "ac_open2", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern Int32 _ac_open2(IntPtr PAc_instance, [MarshalAs(UnmanagedType.LPStr)]string Filename); - - public static Int32 ac_open2(IntPtr PAc_instance, string Filename) - { - lock (_lock) - { - return _ac_open2(PAc_instance, Filename); - } - } // Closes an opened media file. //procedure ac_close(inst: PAc_instance);cdecl; external ac_dll; @@ -327,28 +316,6 @@ namespace Vocaluxe.Lib.Video.Acinerella return _ac_create_decoder(PAc_instance, nb); } } - - [DllImport(AcDll, EntryPoint = "ac_create_audio_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_audio_decoder(IntPtr PAc_instance); - - public static IntPtr ac_create_audio_decoder(IntPtr PAc_instance) - { - lock (_lock) - { - return _ac_create_audio_decoder(PAc_instance); - } - } - - [DllImport(AcDll, EntryPoint = "ac_create_video_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_video_decoder(IntPtr PAc_instance); - - public static IntPtr ac_create_video_decoder(IntPtr PAc_instance) - { - lock (_lock) - { - return _ac_create_video_decoder(PAc_instance); - } - } // Frees an created decoder. //procedure ac_free_decoder(pDecoder: PAc_decoder); cdecl; external ac_dll; diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.c b/Vocaluxe/Lib/Video/Acinerella/acinerella.c index 5436d589..3550bc07 100644 --- a/Vocaluxe/Lib/Video/Acinerella/acinerella.c +++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #define AUDIO_BUFFER_BASE_SIZE AVCODEC_MAX_AUDIO_FRAME_SIZE @@ -81,8 +80,8 @@ struct _ac_audio_decoder { ac_decoder decoder; int sought; double last_timecode; - //uint8_t *tmp_data; - //int tmp_data_length; + uint8_t *tmp_data; + int tmp_data_length; int max_buffer_size; AVCodec *pCodec; AVCodecContext *pCodecCtx; @@ -205,7 +204,7 @@ lp_ac_proberesult CALL_CONVT ac_probe_input_buffer( return (lp_ac_proberesult)fmt; } -#define PROBE_BUF_MIN 1024 +#define PROBE_BUF_MIN 2048 #define PROBE_BUF_MAX (1<<20) @@ -339,7 +338,7 @@ int CALL_CONVT ac_open( //Retrieve stream information AVFormatContext *ctx = ((lp_ac_data)pacInstance)->pFormatCtx; if(avformat_find_stream_info(ctx, NULL) >= 0) { - pacInstance->info.duration = ctx->duration * 1000 / AV_TIME_BASE; + pacInstance->info.duration = ctx->duration * 1000 / AV_TIME_BASE; } else { return -1; } @@ -351,39 +350,6 @@ int CALL_CONVT ac_open( return 0; } -int CALL_CONVT ac_open2(lp_ac_instance pacInstance, const char* filename) -{ - pacInstance->opened = 0; - - //Store the given parameters in the ac Instance - ((lp_ac_data)pacInstance)->sender = NULL; - ((lp_ac_data)pacInstance)->open_proc = NULL; - ((lp_ac_data)pacInstance)->read_proc = NULL; - ((lp_ac_data)pacInstance)->seek_proc = NULL; - ((lp_ac_data)pacInstance)->close_proc = NULL; - - /* open input file, and allocate format context */ - int ret = 0; - if ((ret = avformat_open_input(&((lp_ac_data)pacInstance)->pFormatCtx, filename, NULL, NULL)) < 0) - { - return ret; - } - - /* retrieve stream information */ - if ((ret = avformat_find_stream_info(((lp_ac_data)pacInstance)->pFormatCtx, NULL)) < 0) - { - return ret; - } - else - pacInstance->info.duration = ((lp_ac_data)pacInstance)->pFormatCtx->duration * 1000 / AV_TIME_BASE; - - //Set some information in the instance variable - pacInstance->stream_count = ((lp_ac_data)pacInstance)->pFormatCtx->nb_streams; - pacInstance->opened = pacInstance->stream_count > 0; - - return 0; -} - void CALL_CONVT ac_close(lp_ac_instance pacInstance) { if (pacInstance->opened) { //Close the opened file @@ -438,13 +404,42 @@ void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, lp_ac_str info->stream_type = AC_STREAM_TYPE_AUDIO; //Store more information about the video stream - info->audio_info.samples_per_second = + info->audio_info.samples_per_second = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_rate; - info->audio_info.channel_count = 2; - //((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->channels; - - // Set bit depth (its always 16Bit because of the conversion! - info->audio_info.bit_depth = 16; + info->audio_info.channel_count = + ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->channels; + + // Set bit depth + switch (((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_fmt) { + //8-Bit + case AV_SAMPLE_FMT_U8: + info->audio_info.bit_depth = + 8; + break; + + //16-Bit + case AV_SAMPLE_FMT_S16: + info->audio_info.bit_depth = + 16; + break; + +/* //24-Bit (removed in the newest ffmpeg version) + case SAMPLE_FMT_S24: + info->additional_info.audio_info.bit_depth = + 24; + break; */ + + //32-Bit + case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_FLT: + info->audio_info.bit_depth = + 32; + break; + + //Unknown format, return zero + default: + info->audio_info.bit_depth = + 0; + } break; default: @@ -506,189 +501,89 @@ enum PixelFormat convert_pix_format(ac_output_format fmt) { } //Init a video decoder -void* _ac_create_video_decoder(lp_ac_instance pacInstance, lp_ac_stream_info info, int nb) { - //Allocate memory for a new decoder instance - lp_ac_video_decoder pDecoder; - pDecoder = (lp_ac_video_decoder)(av_malloc(sizeof(ac_video_decoder))); - memset(pDecoder, 0, sizeof(ac_video_decoder)); +void* ac_create_video_decoder(lp_ac_instance pacInstance, lp_ac_stream_info info, int nb) { + //Allocate memory for a new decoder instance + lp_ac_video_decoder pDecoder; + pDecoder = (lp_ac_video_decoder)(av_malloc(sizeof(ac_video_decoder))); + memset(pDecoder, 0, sizeof(ac_video_decoder)); + + //Set a few properties + pDecoder->decoder.pacInstance = pacInstance; + pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO; + pDecoder->decoder.stream_index = nb; + pDecoder->pCodecCtx = ((lp_ac_data)(pacInstance))->pFormatCtx->streams[nb]->codec; + pDecoder->decoder.stream_info = *info; + + //Find correspondenting codec + if (!(pDecoder->pCodec = avcodec_find_decoder(pDecoder->pCodecCtx->codec_id))) { + return NULL; //Codec could not have been found + } - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO; - pDecoder->decoder.stream_index = nb; - pDecoder->pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->decoder.stream_info = *info; - pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pDecoder->pCodecCtx->codec_id))) - return NULL; //Codec could not have been found + pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be + // tested if there is a better solution - //Open codec - if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; //Codec could not have been opened + //Open codec + if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) { + return NULL; //Codec could not have been opened + } + + //Reserve frame variables + pDecoder->pFrame = avcodec_alloc_frame(); + pDecoder->pFrameRGB = avcodec_alloc_frame(); + + pDecoder->pSwsCtx = NULL; + + //Reserve buffer memory + pDecoder->decoder.buffer_size = avpicture_get_size(convert_pix_format(pacInstance->output_format), + pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); + pDecoder->decoder.pBuffer = (uint8_t*)av_malloc(pDecoder->decoder.buffer_size); - //Reserve frame variables - pDecoder->pFrame = avcodec_alloc_frame(); - pDecoder->pFrameRGB = avcodec_alloc_frame(); - - pDecoder->pSwsCtx = NULL; - - //Reserve buffer memory - pDecoder->decoder.buffer_size = avpicture_get_size(convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - pDecoder->decoder.pBuffer = (uint8_t*)av_malloc(pDecoder->decoder.buffer_size); - - //Link decoder to buffer - avpicture_fill( - (AVPicture*)(pDecoder->pFrameRGB), - pDecoder->decoder.pBuffer, convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - - return (void*)pDecoder; + //Link decoder to buffer + avpicture_fill( + (AVPicture*)(pDecoder->pFrameRGB), + pDecoder->decoder.pBuffer, convert_pix_format(pacInstance->output_format), + pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); + + return (void*)pDecoder; } - - //Init a audio decoder -void* _ac_create_audio_decoder(lp_ac_instance pacInstance, lp_ac_stream_info info, int nb) { - //Allocate memory for a new decoder instance - lp_ac_audio_decoder pDecoder; - pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder))); - memset(pDecoder, 0, sizeof(ac_audio_decoder)); - - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_AUDIO; - pDecoder->decoder.stream_index = nb; - pDecoder->decoder.stream_info = *info; - pDecoder->decoder.video_clock = 0; - - //Temporary store codec context pointer - AVCodecContext *pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->pCodecCtx = pCodecCtx; - pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pCodecCtx->codec_id))) - return NULL; - - //Open codec - if (avcodec_open2(pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; - - //Initialize the buffers - pDecoder->decoder.pBuffer = av_malloc(AUDIO_BUFFER_BASE_SIZE); - pDecoder->decoder.buffer_size = 0; - pDecoder->max_buffer_size = AUDIO_BUFFER_BASE_SIZE; - - //pDecoder->tmp_data = NULL; - //pDecoder->tmp_data_length = 0; - - return (void*)pDecoder; -} - -lp_ac_decoder CALL_CONVT ac_create_video_decoder(lp_ac_instance pacInstance) { - //Allocate memory for a new decoder instance - lp_ac_video_decoder pDecoder; - pDecoder = (lp_ac_video_decoder)(av_malloc(sizeof(ac_video_decoder))); - memset(pDecoder, 0, sizeof(ac_video_decoder)); - - int nb = av_find_best_stream(((lp_ac_data)pacInstance)->pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); - if (nb < 0) - return NULL; - - ac_stream_info info; - ac_get_stream_info(pacInstance, nb, &info); - - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO; - pDecoder->decoder.stream_index = nb; - pDecoder->decoder.video_clock = 0; - ((lp_ac_decoder_data)pDecoder)->last_timecode = 0; - ((lp_ac_decoder_data)pDecoder)->sought = 1; - pDecoder->pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->decoder.stream_info = info; - pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pDecoder->pCodecCtx->codec_id))) - return NULL; //Codec could not have been found - - //Open codec - if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; //Codec could not have been opened - - //Reserve frame variables - pDecoder->pFrame = avcodec_alloc_frame(); - pDecoder->pFrameRGB = avcodec_alloc_frame(); - - pDecoder->pSwsCtx = NULL; - - //Reserve buffer memory - pDecoder->decoder.buffer_size = avpicture_get_size(convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - pDecoder->decoder.pBuffer = (uint8_t*)av_malloc(pDecoder->decoder.buffer_size); - - //Link decoder to buffer - avpicture_fill( - (AVPicture*)(pDecoder->pFrameRGB), - pDecoder->decoder.pBuffer, convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - - return (void*)pDecoder; -} - -lp_ac_decoder CALL_CONVT ac_create_audio_decoder(lp_ac_instance pacInstance) -{ - //Allocate memory for a new decoder instance - lp_ac_audio_decoder pDecoder; - pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder))); - memset(pDecoder, 0, sizeof(ac_audio_decoder)); - - int nb = av_find_best_stream(((lp_ac_data)pacInstance)->pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); - if (nb < 0) - return NULL; - - ac_stream_info info; - ac_get_stream_info(pacInstance, nb, &info); +void* ac_create_audio_decoder(lp_ac_instance pacInstance, lp_ac_stream_info info, int nb) { + //Allocate memory for a new decoder instance + lp_ac_audio_decoder pDecoder; + pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder))); + memset(pDecoder, 0, sizeof(ac_audio_decoder)); - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_AUDIO; - pDecoder->decoder.stream_index = nb; - pDecoder->decoder.stream_info = info; - pDecoder->decoder.video_clock = 0; - ((lp_ac_decoder_data)pDecoder)->last_timecode = 0; - ((lp_ac_decoder_data)pDecoder)->sought = 1; - - //Temporary store codec context pointer - AVCodecContext *pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->pCodecCtx = pCodecCtx; - pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pCodecCtx->codec_id))) - return NULL; + //Set a few properties + pDecoder->decoder.pacInstance = pacInstance; + pDecoder->decoder.type = AC_DECODER_TYPE_AUDIO; + pDecoder->decoder.stream_index = nb; + pDecoder->decoder.stream_info = *info; + pDecoder->decoder.video_clock = 0; + + //Temporary store codec context pointer + AVCodecContext *pCodecCtx = ((lp_ac_data)(pacInstance))->pFormatCtx->streams[nb]->codec; + pDecoder->pCodecCtx = pCodecCtx; + + //Find correspondenting codec + if (!(pDecoder->pCodec = avcodec_find_decoder(pCodecCtx->codec_id))) { + return NULL; + } + + //Open codec + if (avcodec_open2(pCodecCtx, pDecoder->pCodec, NULL) < 0) { + return NULL; + } - //Open codec - if (avcodec_open2(pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; - - //Initialize the buffers - pDecoder->decoder.pBuffer = av_malloc(AUDIO_BUFFER_BASE_SIZE); - pDecoder->decoder.buffer_size = 0; - pDecoder->max_buffer_size = AUDIO_BUFFER_BASE_SIZE; - - //pDecoder->tmp_data = NULL; - //pDecoder->tmp_data_length = 0; - - return (void*)pDecoder; + //Initialize the buffers + pDecoder->decoder.pBuffer = NULL; //av_malloc(AUDIO_BUFFER_BASE_SIZE); + pDecoder->decoder.buffer_size = 0; + pDecoder->max_buffer_size = 0; + + pDecoder->tmp_data = NULL; + pDecoder->tmp_data_length = 0; + + return (void*)pDecoder; } lp_ac_decoder CALL_CONVT ac_create_decoder(lp_ac_instance pacInstance, int nb) { @@ -700,15 +595,12 @@ lp_ac_decoder CALL_CONVT ac_create_decoder(lp_ac_instance pacInstance, int nb) { lp_ac_decoder result; if (info.stream_type == AC_STREAM_TYPE_VIDEO) { - result = _ac_create_video_decoder(pacInstance, &info, nb); + result = ac_create_video_decoder(pacInstance, &info, nb); } else if (info.stream_type == AC_STREAM_TYPE_AUDIO) { - result = _ac_create_audio_decoder(pacInstance, &info, nb); + result = ac_create_audio_decoder(pacInstance, &info, nb); } - if (result == NULL) - return NULL; - ((lp_ac_decoder_data)result)->last_timecode = 0; ((lp_ac_decoder_data)result)->sought = 1; result->video_clock = 0; @@ -751,7 +643,13 @@ int ac_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder pkt_tmp.size -= len; pkt_tmp.data += len; } - + + /* + avcodec_decode_video2( + pDecoder->pCodecCtx, pDecoder->pFrame, &finished, + &(((lp_ac_package_data)pPackage)->ffpackage)); + */ + if (finished != 0) { pDecoder->pSwsCtx = sws_getCachedContext(pDecoder->pSwsCtx, pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt, @@ -789,18 +687,6 @@ int ac_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder return 0; } -int alloc_samples_array_and_data(uint8_t ***data, int *linesize, int nb_channels, - int nb_samples, enum AVSampleFormat sample_fmt, int align) -{ - int nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; - - *data = av_malloc(sizeof(*data) * nb_planes); - if (!*data) - return AVERROR(ENOMEM); - return av_samples_alloc(*data, linesize, nb_channels, - nb_samples, sample_fmt, align); -} - int ac_decode_audio_package(lp_ac_package pPackage, lp_ac_audio_decoder pDecoder, lp_ac_decoder pDec) { double pts; //Variables describing the destination buffer @@ -808,18 +694,17 @@ int ac_decode_audio_package(lp_ac_package pPackage, lp_ac_audio_decoder pDecoder //Make a copy of the package read by avformat, so that we can move the data pointers around AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage; - + AVFrame *decoded_frame = NULL; - - /* + if (pDecoder->tmp_data_length > 0) { pkt_tmp.data = av_realloc(pkt_tmp.data, pkt_tmp.size + pDecoder->tmp_data_length); - memmove(pkt_tmp.data + pDecoder->tmp_data_length, pkt_tmp.data, pkt_tmp.size); - memcpy(pkt_tmp.data, pDecoder->tmp_data, pDecoder->tmp_data_length); pkt_tmp.size = pkt_tmp.size + pDecoder->tmp_data_length; - } */ - + memcpy(pkt_tmp.data + pDecoder->tmp_data_length, &pkt_tmp.data, pkt_tmp.size); + memcpy(&pkt_tmp.data, pDecoder->tmp_data, pDecoder->tmp_data_length); + } + while (pkt_tmp.size > 0) { if (!decoded_frame) { @@ -833,6 +718,7 @@ int ac_decode_audio_package(lp_ac_package pPackage, lp_ac_audio_decoder pDecoder int len1 = avcodec_decode_audio4(pDecoder->pCodecCtx, decoded_frame, &got_frame, &pkt_tmp); + //If an error occured, skip the frame if (len1 < 0){ return 0; @@ -843,107 +729,54 @@ int ac_decode_audio_package(lp_ac_package pPackage, lp_ac_audio_decoder pDecoder pkt_tmp.data += len1; if (got_frame){ - struct SwrContext *swr_ctx; - int dst_nb_samples = 0, max_dst_nb_samples = 0, dst_linesize = 0; - uint8_t **dst_data = NULL; - int ret = 0; - int dst_sample_rate = (pDecoder->pCodecCtx)->sample_rate; - - swr_ctx = swr_alloc(); - /* set options */ - av_opt_set_int(swr_ctx, "in_channel_layout", (pDecoder->pCodecCtx)->channel_layout, 0); - av_opt_set_int(swr_ctx, "in_sample_rate", (pDecoder->pCodecCtx)->sample_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", (pDecoder->pCodecCtx)->sample_fmt, 0); - - av_opt_set_int(swr_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); - av_opt_set_int(swr_ctx, "out_sample_rate", dst_sample_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); - - if (swr_init(swr_ctx) < 0) - return 0; - - /* compute the number of converted samples: buffering is avoided - * ensuring that the output buffer will contain at least all the - * converted input samples */ - max_dst_nb_samples = dst_nb_samples = av_rescale_rnd( - decoded_frame->nb_samples, dst_sample_rate, (pDecoder->pCodecCtx)->sample_rate, AV_ROUND_UP); - - if (alloc_samples_array_and_data(&dst_data, &dst_linesize, 2, dst_nb_samples, AV_SAMPLE_FMT_S16, 0) < 0) - return 0; - - /* compute destination number of samples */ - dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, (pDecoder->pCodecCtx)->sample_rate) + - decoded_frame->nb_samples, dst_sample_rate, (pDecoder->pCodecCtx)->sample_rate, AV_ROUND_UP); - - if (dst_nb_samples > max_dst_nb_samples) { - av_free(dst_data[0]); - ret = av_samples_alloc(dst_data, &dst_linesize, 2, - dst_nb_samples, AV_SAMPLE_FMT_S16, 1); - if (ret < 0) - return 0; - max_dst_nb_samples = dst_nb_samples; - } - - if ((ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)decoded_frame->data, decoded_frame->nb_samples)) < 0) - return 0; - - int data_size = av_samples_get_buffer_size(&dst_linesize, 2, ret, AV_SAMPLE_FMT_S16, 1); - - //Reserve enough memory for coping the result data - if (dest_buffer_pos + data_size > pDecoder->max_buffer_size) { - pDecoder->decoder.pBuffer = av_realloc(pDecoder->decoder.pBuffer, dest_buffer_pos + data_size); - pDecoder->max_buffer_size = dest_buffer_pos + data_size; - } - - memcpy(pDecoder->decoder.pBuffer + dest_buffer_pos, dst_data[0], data_size); - - //Increment the destination buffer pointers, copy the result to the output buffer - dest_buffer_pos += data_size; - pDecoder->decoder.buffer_size += data_size; - - pts=0; - - if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){ - pts = ((lp_ac_package_data)pPackage)->ffpackage.dts * av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); + int data_size = av_samples_get_buffer_size(NULL, (pDecoder->pCodecCtx)->channels, + decoded_frame->nb_samples, + (pDecoder->pCodecCtx)->sample_fmt, 1); + + //Reserve enough memory for coping the result data + if (dest_buffer_pos + data_size > pDecoder->max_buffer_size) { + pDecoder->decoder.pBuffer = av_realloc(pDecoder->decoder.pBuffer, dest_buffer_pos + data_size); + pDecoder->max_buffer_size = dest_buffer_pos + data_size; + } + memcpy(pDecoder->decoder.pBuffer + dest_buffer_pos, decoded_frame->data[0], data_size); - pDec->video_clock = pts; - } else { - pts = pDec->video_clock; - } + //Increment the destination buffer pointers, copy the result to the output buffer + dest_buffer_pos += data_size; + pDecoder->decoder.buffer_size += data_size; - double bytes_per_second = 4 * pDec->stream_info.audio_info.samples_per_second; - if (bytes_per_second > 0) - pDec->video_clock += data_size / bytes_per_second; + + pts=0; + + if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){ + pts = ((lp_ac_package_data)pPackage)->ffpackage.dts * av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); + + pDec->video_clock = pts; + } else { + pts = pDec->video_clock; + } + + double bytes_per_second = 2 * pDec->stream_info.audio_info.samples_per_second * pDec->stream_info.audio_info.channel_count; + if (bytes_per_second > 0) + pDec->video_clock += data_size / bytes_per_second; - pDec->timecode = pts; - - /* - if (pkt_tmp.size > 0) - { - pDecoder->tmp_data = av_malloc(pkt_tmp.size); - memcpy(pDecoder->tmp_data, pkt_tmp.data, pkt_tmp.size); - pDecoder->tmp_data_length = pkt_tmp.size; - } else { - if (pDecoder->tmp_data_length > 0) - { - av_free(pDecoder->tmp_data); - pDecoder->tmp_data_length = 0; - } - } - */ - - if (dst_data) - av_freep(&dst_data[0]); - av_freep(&dst_data); - - swr_free(&swr_ctx); - return 1; + pDec->timecode = pts; + + if (pkt_tmp.size > 0) + { + pDecoder->tmp_data = av_malloc(pkt_tmp.size); + memcpy(pDecoder->tmp_data, &pkt_tmp.data, pkt_tmp.size); + } else { + av_free(pDecoder->tmp_data); + pDecoder->tmp_data_length = 0; + } + + return 1; } } - //av_free(pDecoder->tmp_data); - //pDecoder->tmp_data_length = 0; + av_free(pDecoder->tmp_data); + pDecoder->tmp_data_length; return 0; } @@ -1019,10 +852,11 @@ int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDec while(done == 0 && pPackage != NULL){ if (((lp_ac_package_data)pPackage)->package.stream_index == pDecoder->stream_index){ done = ac_decode_package(pPackage, pDecoder); + ac_free_package(pPackage); - //if (((lp_ac_audio_decoder)pDecoder)->decoder.buffer_size < 17640) - // done = 0; + if (((lp_ac_audio_decoder)pDecoder)->decoder.buffer_size < 4096) + done = 0; if (done == 0) pPackage = ac_read_package(pacInstance); @@ -1118,8 +952,8 @@ int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos) { if (((lp_ac_audio_decoder)pDecoder)->pCodecCtx->codec->flush != NULL) avcodec_flush_buffers(((lp_ac_audio_decoder)pDecoder)->pCodecCtx); - //av_free(((lp_ac_audio_decoder)pDecoder)->tmp_data); - //((lp_ac_audio_decoder)pDecoder)->tmp_data_length = 0; + av_free(((lp_ac_audio_decoder)pDecoder)->tmp_data); + ((lp_ac_audio_decoder)pDecoder)->tmp_data_length = 0; } return 1; } @@ -1152,7 +986,7 @@ void ac_free_audio_decoder(lp_ac_audio_decoder pDecoder) { av_free(pDecoder->decoder.pBuffer); //Free the memory reserved for the temporary audio buffer - //av_free(pDecoder->tmp_data); + av_free(pDecoder->tmp_data); //Free reserved memory for decoder record av_free(pDecoder); diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.h b/Vocaluxe/Lib/Video/Acinerella/acinerella.h index 064eff6f..203d8750 100644 --- a/Vocaluxe/Lib/Video/Acinerella/acinerella.h +++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.h @@ -113,7 +113,7 @@ struct _ac_audio_stream_info { /*Bits per sample. Can be 8 or 16 Bit.*/ int bit_depth; /*Count of channels in the audio stream.*/ - int channel_count; + int channel_count; }; typedef struct _ac_audio_stream_info ac_audio_stream_info; @@ -205,12 +205,6 @@ extern int CALL_CONVT ac_open( ac_seek_callback seek_proc, ac_openclose_callback close_proc, lp_ac_proberesult proberesult); - -extern int CALL_CONVT ac_open2( - lp_ac_instance pacInstance, - const char* filename -); - /*Closes an opened media file.*/ extern void CALL_CONVT ac_close(lp_ac_instance pacInstance); @@ -225,8 +219,6 @@ extern void CALL_CONVT ac_free_package(lp_ac_package pPackage); /*Creates an decoder for the specified stream number. Returns NIL if no decoder could be found.*/ extern lp_ac_decoder CALL_CONVT ac_create_decoder(lp_ac_instance pacInstance, int nb); -extern lp_ac_decoder CALL_CONVT ac_create_audio_decoder(lp_ac_instance pacInstance); -extern lp_ac_decoder CALL_CONVT ac_create_video_decoder(lp_ac_instance pacInstance); /*Frees an created decoder.*/ extern void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder); /*Decodes a package using the specified decoder. The decodec data is stored in the diff --git a/Vocaluxe/Lib/Video/Acinerella/makefile b/Vocaluxe/Lib/Video/Acinerella/makefile index cf3c9325..1a823680 100644 --- a/Vocaluxe/Lib/Video/Acinerella/makefile +++ b/Vocaluxe/Lib/Video/Acinerella/makefile @@ -2,9 +2,9 @@ acinerella: acinerella.c acinerella.h gcc -c acinerella.c -I /usr/local/include ifeq ($(shell uname),Linux) - gcc -shared -o libacinerella.so acinerella.o -lavformat -lavcodec -lavutil -lm -lswscale -lswresample + gcc -shared -o libacinerella.so acinerella.o -lavformat -lavcodec -lavutil -lm -lswscale strip libacinerella.so else - gcc -shared -o acinerella.dll -fPIC acinerella.o -lavformat -lavcodec -lavutil -lm -lswscale -lws2_32 -lswresample + gcc -shared -o acinerella.dll -fPIC acinerella.o -lavformat -lavcodec -lavutil -lm -lswscale -lws2_32 strip acinerella.dll endif diff --git a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs index 781743f1..9b0f7828 100644 --- a/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs +++ b/Vocaluxe/Lib/Video/CVideoDecoderFFmpeg.cs @@ -223,6 +223,10 @@ namespace Vocaluxe.Lib.Video private int _StreamID; // stream ID for stream closing private string _FileName; // current video file name + private FileStream _fs; // video file stream + private TAc_read_callback _rc; // read callback for acinerella + private TAc_seek_callback _sc; // seek callback for acinerella + private bool _FileOpened = false; private float _VideoTimeBase = 0f; // frame time @@ -255,13 +259,16 @@ namespace Vocaluxe.Lib.Video private bool _terminated = false; private Thread _thread; + //AutoResetEvent EventDecode = new AutoResetEvent(false); SFrameBuffer[] _FrameBuffer = new SFrameBuffer[5]; private bool _NewFrame = false; Object MutexFramebuffer = new Object(); Object MutexSyncSignals = new Object(); public Decoder() - { + { + _rc = new TAc_read_callback(read_proc); + _sc = new TAc_seek_callback(seek_proc); _thread = new Thread(Execute); } @@ -354,6 +361,7 @@ namespace Vocaluxe.Lib.Video UploadNewFrame(ref frame); + //EventDecode.Set(); return true; } @@ -365,6 +373,7 @@ namespace Vocaluxe.Lib.Video } UploadNewFrame(ref frame); VideoTime = _CurrentVideoTime; + //EventDecode.Set(); return true; } return false; @@ -380,6 +389,7 @@ namespace Vocaluxe.Lib.Video _NoMoreFrames = false; _Finished = false; } + //EventDecode.Set(); return true; } @@ -434,14 +444,17 @@ namespace Vocaluxe.Lib.Video _BufferFull = false; _skip = false; _NewFrame = false; + //EventDecode.Set(); } private void Execute() { DoOpen(); + //EventDecode.Set(); while (!_terminated) { + //if (EventDecode.WaitOne(10)) { lock (MutexSyncSignals) { @@ -472,45 +485,56 @@ namespace Vocaluxe.Lib.Video private void DoOpen() { + bool ok = false; TAc_instance Instance = new TAc_instance(); - - _instance = CAcinerella.ac_init(); - int ret = -1; - if ((ret = CAcinerella.ac_open2(_instance, _FileName)) < 0) - { - CLog.LogError("Error opening video file (Errorcode: " + ret.ToString() + "): " + _FileName); - return; - } - - Instance = (TAc_instance)Marshal.PtrToStructure(_instance, typeof(TAc_instance)); - - if (!Instance.opened || Instance.info.duration == 0) - { - if (!Instance.opened) - CLog.LogError("Can't open video file: " + _FileName); - else - CLog.LogError("Can't open video file (length = 0?): " + _FileName); - return; - } - try { - _videodecoder = CAcinerella.ac_create_video_decoder(_instance); - } - catch (Exception e) - { - CLog.LogError("Can't create video decoder for file: " + _FileName + "; " + e.Message); - return; - } + _fs = new FileStream(_FileName, FileMode.Open, FileAccess.Read, FileShare.Read); - if (_videodecoder == IntPtr.Zero) + + _instance = CAcinerella.ac_init(); + CAcinerella.ac_open(_instance, IntPtr.Zero, null, _rc, _sc, null, IntPtr.Zero); + + Instance = (TAc_instance)Marshal.PtrToStructure(_instance, typeof(TAc_instance)); + ok = true; + } + catch (Exception) { - CLog.LogError("Can't create video decoder for file: " + _FileName); + CLog.LogError("Error opening video file: " + _FileName); + ok = false; + } + + + if (!Instance.opened || !ok) + { + //Free(); return; } _Duration = (float)Instance.info.duration / 1000f; + int VideoStreamIndex = -1; + + TAc_stream_info Info = new TAc_stream_info(); + for (int i = 0; i < Instance.stream_count; i++) + { + CAcinerella.ac_get_stream_info(_instance, i, out Info); + + if (Info.stream_type == TAc_stream_type.AC_STREAM_TYPE_VIDEO) + { + _videodecoder = CAcinerella.ac_create_decoder(_instance, i); + + VideoStreamIndex = i; + break; + } + } + + if (VideoStreamIndex < 0) + { + //Free(); + return; + } + TAc_decoder Videodecoder = (TAc_decoder)Marshal.PtrToStructure(_videodecoder, typeof(TAc_decoder)); _Width = Videodecoder.stream_info.video_info.frame_width; @@ -677,6 +701,9 @@ namespace Vocaluxe.Lib.Video _NewFrame = false; } } + + //if (!_BufferFull) + // EventDecode.Set(); } private void UploadNewFrame(ref STexture frame) @@ -705,6 +732,7 @@ namespace Vocaluxe.Lib.Video _CurrentVideoTime = _FrameBuffer[num].time; } _Finished = false; + //EventDecode.Set(); } else { @@ -758,5 +786,23 @@ namespace Vocaluxe.Lib.Video _Closeproc(_StreamID); } #endregion Threading + + #region Callbacks + private Int32 read_proc(IntPtr sender, IntPtr buf, Int32 size) + { + Int32 r = 0; + + byte[] bb = new byte[size]; + r = _fs.Read(bb, 0, size); + Marshal.Copy(bb, 0, buf, size); + + return r; + } + + private Int64 seek_proc(IntPtr sender, Int64 pos, Int32 whence) + { + return (Int64)_fs.Seek((long)pos, (SeekOrigin)whence); + } + #endregion Callbacks } }