diff --git a/.appveyor/afterDeploy.ps1 b/.appveyor/afterDeploy.ps1
new file mode 100644
index 00000000..6fda8b82
--- /dev/null
+++ b/.appveyor/afterDeploy.ps1
@@ -0,0 +1,9 @@
+Write-Host "Deployment finished -> do en empty commit on the gh-pages branch to update the page"
+cd ..
+git clone -q "https://github.com/Vocaluxe/Vocaluxe.git" -b "gh-pages" --single-branch "VocaluxeWeb"
+cd VocaluxeWeb
+git config --global user.email "noreply@vocaluxe.org"
+git config --global user.name "VocaluxeBuildBot"
+git commit --allow-empty -m "Trigger page update after a new publish (triggered by $Env:APPVEYOR_REPO_COMMIT_MESSAGE [$Env:APPVEYOR_REPO_COMMIT])"
+git push -q "https://$($Env:GitHubKey):x-oauth-basic@github.com/Vocaluxe/Vocaluxe.git" "gh-pages"
+cd ..\Vocaluxe
\ No newline at end of file
diff --git a/.appveyor/prepareDeploy.ps1 b/.appveyor/prepareDeploy.ps1
index 922a6550..e9db2bc9 100644
--- a/.appveyor/prepareDeploy.ps1
+++ b/.appveyor/prepareDeploy.ps1
@@ -7,6 +7,8 @@ else{
Return;
}
+$Env:IS_BETA_RELEASE = ($Env:APPVEYOR_REPO_TAG_NAME -match "beta")
+
$getRelaseInfoParams = @{
Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/tags/$targetTag";
Method = 'GET';
@@ -23,20 +25,26 @@ catch [System.Net.WebException]
# No Release found for this tag
$statusCode = [int]$_.Exception.Response.StatusCode
$html = $_.Exception.Response.StatusDescription
- Write-Host "No Release found for this tag ($html): $($Env:APPVEYOR_REPO_TAG_NAME)"
+ Write-Host "No Release found for this tag ($html): $targetTag"
Return;
}
-$assetId = ($result.assets | where {$_.name -EQ "Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip" } | Select-Object -first 1 ).id
+$releaseId = $result.id
-if(!$assetId){
- # No matching asset found in this release
- Write-Host "No matching asset found in this release: Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip"
+if(!$releaseId){
+ # No matching release found in this release
+ Write-Host "No matching release found"
+ Return;
+}
+
+if($result.body -match $Env:APPVEYOR_REPO_COMMIT){
+ # An other build already recreated the release
+ Write-Host "An other build already recreated the release"
Return;
}
$deleteAssetParams = @{
- Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/assets/$assetId";
+ Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/$releaseId";
Method = 'DELETE';
Headers = @{
Authorization = 'Basic ' + [Convert]::ToBase64String(
@@ -45,14 +53,14 @@ $deleteAssetParams = @{
}
try{
$result = Invoke-RestMethod @deleteAssetParams
- Write-Host "Successfully deleted asset: Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip"
+ Write-Host "Successfully deleted release for: $targetTag"
}
catch [System.Net.WebException]
{
- # Could not delete asset
+ # Could not delete release
$statusCode = [int]$_.Exception.Response.StatusCode
$html = $_.Exception.Response.StatusDescription
- Write-Host "Could not delete asset ($html): Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip"
+ Write-Host "Could not delete release ($html) for: $targetTag"
Return;
}
\ No newline at end of file
diff --git a/Output/Languages/Czech.xml b/Output/Languages/Czech.xml
index a34fe68f..fe288daf 100644
--- a/Output/Languages/Czech.xml
+++ b/Output/Languages/Czech.xml
@@ -73,6 +73,8 @@
Celkem
Normální
Rozšířené
+ Uvést vše
+ Uvést nejlepší
Vlastní hudba a hudba na pozadí
Žádná vlastní hudba
Pouze vlastní hudba
@@ -183,6 +185,7 @@
Karty
Obtížnost hry
Režim časomíry
+ Styl pro nejlepší výsledky
Nastavení nahrávání
Zařízení
Vstup
@@ -201,6 +204,7 @@
Zdroj hudby na pozadí
Hlasitost ukázky
Hlasitost hry
+ Efekt Karaoke
Nastavení tématu
Téma
Vzhled
diff --git a/Output/Languages/French.xml b/Output/Languages/French.xml
index fe0c7149..5820b536 100644
--- a/Output/Languages/French.xml
+++ b/Output/Languages/French.xml
@@ -46,6 +46,7 @@
Niveau 2
Niveau 3
Max
+ Afficher
Caroussel
Damier
Livre
@@ -72,6 +73,8 @@
Total
Normal
Développé
+ Tout afficher
+ Afficher les meilleurs
Musique personnelle et Musique de fond
Pas de Musique personnelle
Seulement la Musique personnelle
@@ -79,6 +82,10 @@
Tout
Seulement noms et avatars
Rien
+ Remplir
+ Sauter
+ Glisser
+ Zoomer
En bas
En haut
En haut et en bas
@@ -178,6 +185,7 @@
Dossiers
Difficulté du Jeu
Mode du Minuteur
+ Style meilleur score
Options d'Enregistrement
Appareil
Entrée
@@ -196,6 +204,7 @@
Source de la Musique de fond
Volume de la Musique de prévisualisation
Volume de la Musique du jeu
+ Effet Karaoké
Options du Thème
Thème
Environnement graphique
diff --git a/Output/Languages/Italian.xml b/Output/Languages/Italian.xml
index 8fce81fc..57fd6652 100644
--- a/Output/Languages/Italian.xml
+++ b/Output/Languages/Italian.xml
@@ -46,6 +46,7 @@
Livello 2
Livello 3
Max
+ Elenco
Dreidel
Scacchiera
Libro
@@ -72,6 +73,8 @@
Totale
Normale
Espanso
+ Elenco tutti
+ Elenco migliori
Musica personale e musica di sfondo
Nessuna musica personale
Solo musica personale
@@ -79,6 +82,9 @@
Tutto
Solo nomi e avatar
Niente
+ Riempi
+ Salta
+ Zoom
Sotto
Sopra
Sopra e sotto
@@ -196,6 +202,7 @@
Sorgente musica di sfondo
Anteprima volume musica
Volume musica di gioco
+ Effetto karaoke
Opzioni tema
Tema
Skin
diff --git a/Output/PartyModes/Challenge/Languages/Czech.xml b/Output/PartyModes/Challenge/Languages/Czech.xml
index 5dc3a83d..c0fce8eb 100644
--- a/Output/PartyModes/Challenge/Languages/Czech.xml
+++ b/Output/PartyModes/Challenge/Languages/Czech.xml
@@ -15,6 +15,8 @@
Počet hráčů
Počet mikrofonů
Počet kol
+ Počet žolíků
+ Doplnit žolíky každé kolo
Soutěžní režim: Výběr hráče
Vybrat náhodně
Soutěžní režim: Přehled
diff --git a/Output/PartyModes/Challenge/Languages/French.xml b/Output/PartyModes/Challenge/Languages/French.xml
index 7ff1b981..27ece675 100644
--- a/Output/PartyModes/Challenge/Languages/French.xml
+++ b/Output/PartyModes/Challenge/Languages/French.xml
@@ -15,6 +15,8 @@
Nombre de joueurs
Nombre de micros
Nombre de tours
+ Nombre de jokers
+ Remplir de nouveau les jokers à tour
Mode Challenge: Choix des joueurs
Sélectionner au hasard
Mode Challenge: Résumé
diff --git a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs
index 6cf643e5..636e3cfe 100644
--- a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs
+++ b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs
@@ -60,7 +60,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
// ReSharper disable ClassNeverInstantiated.Global
public sealed class CPartyModeTicTacToe : CPartyMode
- // ReSharper restore ClassNeverInstantiated.Global
+ // ReSharper restore ClassNeverInstantiated.Global
{
public override int MinMics
{
@@ -96,7 +96,9 @@ namespace VocaluxeLib.PartyModes.TicTacToe
get { return 10; }
}
- private enum EStage
+ public readonly EGameMode[] AvailableGameModes = { EGameMode.TR_GAMEMODE_NORMAL, EGameMode.TR_GAMEMODE_SHORTSONG, EGameMode.TR_GAMEMODE_DUET };
+
+ private enum EStage
{
Config,
Names,
@@ -119,7 +121,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
public int CategoryIndex;
public int PlaylistID;
- public EGameMode GameMode;
+ public int GameMode;
public List Rounds;
public List Songs;
@@ -160,7 +162,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
SongSource = ESongSource.TR_ALLSONGS,
PlaylistID = 0,
CategoryIndex = 0,
- GameMode = EGameMode.TR_GAMEMODE_NORMAL,
+ GameMode = 0,
Rounds = new List(),
Songs = new List(),
NumJokerRandom = new int[2],
@@ -432,20 +434,20 @@ namespace VocaluxeLib.PartyModes.TicTacToe
for (int i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistID); i++)
{
int id = CBase.Playlist.GetSong(GameData.PlaylistID, i).SongID;
- if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(GameData.GameMode))
+ if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode]))
GameData.Songs.Add(id);
}
break;
case ESongSource.TR_ALLSONGS:
ReadOnlyCollection avSongs = CBase.Songs.GetSongs();
- GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID));
+ GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode])).Select(song => song.ID));
break;
case ESongSource.TR_CATEGORY:
CBase.Songs.SetCategory(GameData.CategoryIndex);
avSongs = CBase.Songs.GetVisibleSongs();
- GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID));
+ GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode])).Select(song => song.ID));
CBase.Songs.SetCategory(-1);
break;
@@ -493,7 +495,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe
if (isDuet)
players[1].VoiceNr = 1;
- CBase.Game.AddSong(round.SongID, GameData.GameMode);
+ CBase.Game.AddSong(round.SongID, AvailableGameModes[GameData.GameMode]);
}
private void _SetNumJokers()
diff --git a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs
index c75cd880..feeda81b 100644
--- a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs
+++ b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs
@@ -160,8 +160,8 @@ namespace VocaluxeLib.PartyModes.TicTacToe
_SelectSlides[_SelectSlideGameMode].Visible = true;
_SelectSlides[_SelectSlideGameMode].Clear();
- _SelectSlides[_SelectSlideGameMode].SetValues((int)_PartyMode.GameData.GameMode);
- _SelectSlides[_SelectSlideGameMode].RemoveValue(EGameMode.TR_GAMEMODE_MEDLEY.ToString());
+ _SelectSlides[_SelectSlideGameMode].AddValues(_PartyMode.AvailableGameModes.Select(gm => gm.ToString()));
+ _SelectSlides[_SelectSlideGameMode].Selection = _PartyMode.GameData.GameMode;
}
private void _UpdateSlides()
@@ -171,9 +171,9 @@ namespace VocaluxeLib.PartyModes.TicTacToe
_PartyMode.GameData.SongSource = (ESongSource)_SelectSlides[_SelectSlideSongSource].Selection;
_PartyMode.GameData.PlaylistID = _SelectSlides[_SelectSlidePlaylist].Selection;
_PartyMode.GameData.CategoryIndex = _SelectSlides[_SelectSlideCategory].Selection;
- _PartyMode.GameData.GameMode = (EGameMode)_SelectSlides[_SelectSlideGameMode].Selection;
+ _PartyMode.GameData.GameMode = _SelectSlides[_SelectSlideGameMode].Selection;
- EGameMode gm = _PartyMode.GameData.GameMode;
+ EGameMode gm = _PartyMode.AvailableGameModes[_PartyMode.GameData.GameMode];
if (_PartyMode.GameData.SongSource == ESongSource.TR_PLAYLIST)
{
diff --git a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs
index 91d4e4e1..6af5d259 100644
--- a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs
+++ b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs
@@ -58,7 +58,22 @@ namespace Vocaluxe.Lib.Video.Acinerella
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct SACFileInfo
{
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
+ public readonly string title;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
+ public readonly string author;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
+ public readonly string copyright;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
+ public readonly string comment;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
+ public readonly string album;
+ public readonly int year;
+ public readonly int track;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public readonly string genre;
public readonly Int64 Duration;
+ public readonly int Bitrate;
}
// TAc_instance represents an Acinerella instance. Each instance can open and
@@ -105,14 +120,17 @@ namespace Vocaluxe.Lib.Video.Acinerella
}
// Contains information about an Acinerella stream.
- [StructLayout(LayoutKind.Sequential)]
+ [StructLayout(LayoutKind.Explicit)]
public struct SACStreamInfo
{
//Contains the type of the stream.
+ [FieldOffset(0)]
public readonly EACStreamType StreamType;
//Additional info about the stream
+ [FieldOffset(8)]
public SACAudioStreamInfo AudioInfo;
+ [FieldOffset(8)]
public SACVideoStreamInfo VideoInfo;
}
@@ -128,7 +146,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
//The timecode of the currently decoded picture in seconds.
public readonly double Timecode;
- public readonly double VideoClock;
+ //public readonly double VideoClock;
//Contains information about the stream the decoder is attached to.
public SACStreamInfo StreamInfo;
@@ -219,14 +237,14 @@ namespace Vocaluxe.Lib.Video.Acinerella
// Initializes an Acinerella instance.
//function ac_init(): PAc_instance; cdecl; external ac_dll;
- [DllImport(_AcDll, EntryPoint = "ac_init", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
- private static extern IntPtr _ac_init();
+ [DllImport(_AcDll, EntryPoint = "ac_init_of", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
+ private static extern IntPtr _ac_init(EACOutputFormat outputFormat);
public static IntPtr AcInit()
{
lock (_Lock)
{
- return _ac_init();
+ return _ac_init(EACOutputFormat.ACOutputRGBA32);
}
}
@@ -243,52 +261,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
}
}
- // Opens a media file.
- // @param(inst specifies the Acinerella Instance the stream should be opened for)
- // @param(sender specifies a pointer that is sent to all callback functions to
- // allow you to do object orientated programming. May be NULL.)
- // @param(open_proc specifies the callback function that is called, when the
- // media file is opened. May be NULL.)
- // @param(close_proc specifies the callback function that is called when the media
- // file is closed. May be NULL.)
- /*function ac_open(
- inst: PAc_instance;
- sender: Pointer;
- open_proc: TAc_openclose_callback;
- read_proc: TAc_read_callback;
- seek_proc: TAc_seek_callback;
- close_proc: TAc_openclose_callback;
- proberesult: PAc_proberesult): integer; cdecl; external ac_dll;
- */
- /*
- [DllImport(AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
- private static extern Int32 _ac_open(
- IntPtr PAc_instance,
- IntPtr sender,
- TAc_openclose_callback open_proc,
- TAc_read_callback read_proc,
- TAc_seek_callback seek_proc,
- TAc_openclose_callback close_proc,
- IntPtr proberesult
- );
-
- public static Int32 ac_open(
- IntPtr PAc_instance,
- IntPtr sender,
- TAc_openclose_callback open_proc,
- TAc_read_callback read_proc,
- TAc_seek_callback seek_proc,
- TAc_openclose_callback close_proc,
- IntPtr proberesult
- )
- {
- lock (_GetLockToken(pAcDecoder))
- {
- return _ac_open(PAc_instance, sender, open_proc, read_proc, seek_proc, close_proc, proberesult);
- }
- }*/
-
- [DllImport(_AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+ [DllImport(_AcDll, EntryPoint = "ac_open_file", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern Int32 _ac_open2(IntPtr pAcInstance, string filename);
// ReSharper disable UnusedMethodReturnValue.Global
@@ -337,28 +310,55 @@ namespace Vocaluxe.Lib.Video.Acinerella
[DllImport(_AcDll, EntryPoint = "ac_free_package", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern void ac_free_package(IntPtr pAcPackage);
- [DllImport(_AcDll, EntryPoint = "ac_create_video_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
- private static extern IntPtr _ac_create_video_decoder(IntPtr pAcInstance);
+ [DllImport(_AcDll, EntryPoint = "ac_create_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
+ private static extern IntPtr _ac_create_decoder(IntPtr pAcInstance, int i);
public static IntPtr AcCreateVideoDecoder(IntPtr pAcInstance)
{
lock (_GetLockToken(pAcInstance))
{
- return _ac_create_video_decoder(pAcInstance);
+ var firstVideoStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeVideo);
+
+ if (firstVideoStreamId < 0)
+ {
+ throw new ArgumentException("The instace does not contain a video stream.");
+ }
+
+ return _ac_create_decoder(pAcInstance, firstVideoStreamId);
}
}
-
- [DllImport(_AcDll, EntryPoint = "ac_create_audio_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
- private static extern IntPtr _ac_create_audio_decoder(IntPtr pAcInstance);
-
+
public static IntPtr AcCreateAudioDecoder(IntPtr pAcInstance)
{
lock (_GetLockToken(pAcInstance))
{
- return _ac_create_audio_decoder(pAcInstance);
+ var firstAudioStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeAudio);
+
+ if (firstAudioStreamId < 0)
+ {
+ throw new ArgumentException("The instace does not contain a audio stream.");
+ }
+ return _ac_create_decoder(pAcInstance, firstAudioStreamId);
}
}
+ private static int _GetFirstStreamByType(IntPtr pAcInstance, EACStreamType type)
+ {
+ var instance = (SACInstance)Marshal.PtrToStructure(pAcInstance, typeof(SACInstance));
+
+ int currentStream = 0;
+ SACStreamInfo currentStreamInfo;
+
+ while (currentStream < instance.StreamCount)
+ {
+ AcGetStreamInfo(pAcInstance, currentStream, out currentStreamInfo);
+ if (currentStreamInfo.StreamType == type)
+ return currentStream;
+ currentStream++;
+ }
+ return -1;
+ }
+
// Frees an created decoder.
//procedure ac_free_decoder(pDecoder: PAc_decoder); cdecl; external ac_dll;
[DllImport(_AcDll, EntryPoint = "ac_free_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs
index a11c1871..38275210 100644
--- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs
+++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs
@@ -447,6 +447,7 @@ namespace Vocaluxe.Lib.Video.Acinerella
{
_Free();
Stop();
+ return;
}
while (!_Terminated)
diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.c b/Vocaluxe/Lib/Video/Acinerella/acinerella.c
index ade729d3..a61fd875 100644
--- a/Vocaluxe/Lib/Video/Acinerella/acinerella.c
+++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.c
@@ -17,73 +17,111 @@
#include
#include
-#include "acinerella.h"
+#include
+
#include
#include
#include
#include
+#include "libavutil/imgutils.h"
#include
#include
-#include
-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
-#define AUDIO_BUFFER_BASE_SIZE AVCODEC_MAX_AUDIO_FRAME_SIZE
+#include "acinerella.h"
-#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
-#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+#define AC_BUFSIZE 1024 * 64
+#define PROBE_BUF_MIN 1024
+#define PROBE_BUF_MAX (1 << 20)
-//This struct represents one Acinerella video object.
-//It contains data needed by FFMpeg.
-
-#define AC_BUFSIZE 1024*64
+#define ERR(E) \
+ { \
+ if (!(E)) { \
+ goto error; \
+ } \
+ }
+#define AV_ERR(E) \
+ { \
+ if ((E) < 0) { \
+ goto error; \
+ } \
+ }
struct _ac_data {
- ac_instance instance;
- AVFormatContext *pFormatCtx;
- void* buffer;
+ ac_instance instance;
+
+ AVFormatContext *pFormatCtx;
+ AVIOContext *pIo;
+
+ void *sender;
+ ac_openclose_callback open_proc;
+ ac_read_callback read_proc;
+ ac_seek_callback seek_proc;
+ ac_openclose_callback close_proc;
+
+ uint8_t *buffer;
+ uint8_t *probe_buffer;
+ size_t probe_buffer_size;
+ size_t probe_buffer_offs;
};
typedef struct _ac_data ac_data;
-typedef ac_data* lp_ac_data;
+typedef ac_data *lp_ac_data;
struct _ac_decoder_data {
- ac_decoder decoder;
+ ac_decoder decoder;
+ int sought;
+ double last_timecode;
};
typedef struct _ac_decoder_data ac_decoder_data;
-typedef ac_decoder_data* lp_ac_decoder_data;
+typedef ac_decoder_data *lp_ac_decoder_data;
struct _ac_video_decoder {
- ac_decoder decoder;
- AVCodec *pCodec;
- AVCodecContext *pCodecCtx;
- AVFrame *pFrame;
- AVFrame *pFrameRGB;
- struct SwsContext *pSwsCtx;
+ ac_decoder decoder;
+ int sought;
+ double last_timecode;
+ AVCodec *pCodec;
+ AVCodecContext *pCodecCtx;
+ AVFrame *pFrame;
+ AVFrame *pFrameRGB;
+ struct SwsContext *pSwsCtx;
};
typedef struct _ac_video_decoder ac_video_decoder;
-typedef ac_video_decoder* lp_ac_video_decoder;
+typedef ac_video_decoder *lp_ac_video_decoder;
struct _ac_audio_decoder {
- ac_decoder decoder;
- int max_buffer_size;
- AVCodec *pCodec;
- AVCodecContext *pCodecCtx;
+ ac_decoder decoder;
+ int sought;
+ double last_timecode;
+ AVCodec *pCodec;
+ AVCodecContext *pCodecCtx;
+ AVFrame *pFrame;
+ SwrContext *pSwrCtx;
+ size_t own_buffer_size;
};
typedef struct _ac_audio_decoder ac_audio_decoder;
-typedef ac_audio_decoder* lp_ac_audio_decoder;
+typedef ac_audio_decoder *lp_ac_audio_decoder;
struct _ac_package_data {
- ac_package package;
- AVPacket ffpackage;
- int pts;
+ ac_package package;
+ AVPacket *pPack;
+ int pts;
};
typedef struct _ac_package_data ac_package_data;
-typedef ac_package_data* lp_ac_package_data;
+typedef ac_package_data *lp_ac_package_data;
+
+//
+//--- Forward declarations ---
+//
+
+void ac_free_video_decoder(lp_ac_video_decoder pDecoder);
+void ac_free_audio_decoder(lp_ac_audio_decoder pDecoder);
//
//--- Initialization and Stream opening---
@@ -91,702 +129,1035 @@ typedef ac_package_data* lp_ac_package_data;
void init_info(lp_ac_file_info info)
{
- info->duration = -1;
+ info->title[0] = 0;
+ info->author[0] = 0;
+ info->copyright[0] = 0;
+ info->comment[0] = 0;
+ info->album[0] = 0;
+ info->year = -1;
+ info->track = -1;
+ info->genre[0] = 0;
+ info->duration = -1;
+ info->bitrate = -1;
}
int av_initialized = 0;
void ac_init_ffmpeg()
{
- if(!av_initialized)
- {
- avcodec_register_all();
- av_register_all();
- av_initialized = 1;
- }
+ if (!av_initialized) {
+ avcodec_register_all();
+ av_register_all();
+
+ av_initialized = 1;
+ }
}
-lp_ac_instance CALL_CONVT ac_init(void) {
- ac_init_ffmpeg();
-
- //Allocate a new instance of the videoplayer data and return it
- lp_ac_data ptmp;
- ptmp = (lp_ac_data)av_malloc(sizeof(ac_data));
-
- //Initialize the created structure
- memset(ptmp, 0, sizeof(ac_data));
-
- ptmp->instance.opened = 0;
- ptmp->instance.stream_count = 0;
- ptmp->instance.output_format = AC_OUTPUT_RGBA32;
- init_info(&(ptmp->instance.info));
- return (lp_ac_instance)ptmp;
+lp_ac_instance CALL_CONVT ac_init(void)
+{
+ ac_init_ffmpeg();
+
+ // Allocate a new instance of the videoplayer data and return it
+ lp_ac_data ptmp;
+ ptmp = (lp_ac_data)av_malloc(sizeof(ac_data));
+
+ // Initialize the created structure
+ memset(ptmp, 0, sizeof(ac_data));
+
+ ptmp->instance.opened = 0;
+ ptmp->instance.stream_count = 0;
+ ptmp->instance.output_format = AC_OUTPUT_BGR24;
+ init_info(&(ptmp->instance.info));
+ return (lp_ac_instance)ptmp;
}
-void CALL_CONVT ac_free(lp_ac_instance pacInstance) {
- //Close the decoder. If it is already closed, this won't be a problem as ac_close checks the streams state
- ac_close(pacInstance);
-
- if (pacInstance != NULL) {
- av_free((lp_ac_data)pacInstance);
- }
+lp_ac_instance CALL_CONVT ac_init_of(ac_output_format outputFormat)
+{
+ ac_init_ffmpeg();
+
+ // Allocate a new instance of the videoplayer data and return it
+ lp_ac_data ptmp;
+ ptmp = (lp_ac_data)av_malloc(sizeof(ac_data));
+
+ // Initialize the created structure
+ memset(ptmp, 0, sizeof(ac_data));
+
+ ptmp->instance.opened = 0;
+ ptmp->instance.stream_count = 0;
+ ptmp->instance.output_format = outputFormat;
+ init_info(&(ptmp->instance.info));
+ return (lp_ac_instance)ptmp;
}
-int CALL_CONVT ac_open(lp_ac_instance pacInstance, const char* filename)
-{
- pacInstance->opened = 0;
-
- /* 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_free(lp_ac_instance pacInstance)
+{
+ if (pacInstance) {
+ // Close the decoder. If it is already closed, this won't be a problem
+ // as
+ // ac_close checks the streams state
+ ac_close(pacInstance);
+ av_free((lp_ac_data)pacInstance);
+ }
}
-void CALL_CONVT ac_close(lp_ac_instance pacInstance) {
- if (pacInstance->opened) {
- //Close the opened file
- avformat_close_input(&(((lp_ac_data)(pacInstance))->pFormatCtx));
- pacInstance->opened = 0;
+static int io_read(void *opaque, uint8_t *buf, int buf_size)
+{
+ lp_ac_data self = ((lp_ac_data)opaque);
- //If the seek proc has not been specified, the input buffer is not automatically
- //freed, as ffmpeg didn't get the original pointer to the buffer
- if (((lp_ac_data)(pacInstance))->buffer) {
- av_free(((lp_ac_data)(pacInstance))->buffer);
+ // If there is still memory in the probe buffer, consume this memory first
+ if (self->probe_buffer &&
+ self->probe_buffer_offs < self->probe_buffer_size) {
+ // Copy as many bytes as possible from the probe buffer
+ size_t cnt =
+ MIN(buf_size, self->probe_buffer_size - self->probe_buffer_offs);
+ memcpy(buf, self->probe_buffer + self->probe_buffer_offs, cnt);
+
+ // Advance the read/write pointers
+ self->probe_buffer_offs += cnt;
+ buf += cnt;
+ buf_size -= (int)cnt;
+
+ // Free the probe buffer once all bytes have been read
+ if (self->probe_buffer_offs == self->probe_buffer_size) {
+ av_free(self->probe_buffer);
+ self->probe_buffer = NULL;
+ self->probe_buffer_size = 0;
+ self->probe_buffer_offs = 0;
+ }
}
- }
+ // Try to read the memory from the probe buffer
+ if (self->read_proc != NULL) {
+ return self->read_proc(self->sender, buf, buf_size);
+ }
+
+ return -1;
}
-void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, lp_ac_stream_info info) {
- if (!(pacInstance->opened)) {
- return;
- }
-
- switch (((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->codec_type) {
- case CODEC_TYPE_VIDEO:
- //Set stream type to "VIDEO"
- info->stream_type = AC_STREAM_TYPE_VIDEO;
-
- //Store more information about the video stream
- info->video_info.frame_width =
- ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->width;
- info->video_info.frame_height =
- ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->height;
-
- double pixel_aspect_num = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_aspect_ratio.num;
- double pixel_aspect_den = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_aspect_ratio.den;
-
- //Sometime "pixel aspect" may be zero or have other invalid values. Correct this.
- if (pixel_aspect_num <= 0.0 || pixel_aspect_den <= 0.0)
- info->video_info.pixel_aspect = 1.0;
- else
- info->video_info.pixel_aspect = pixel_aspect_num / pixel_aspect_den;
-
- info->video_info.frames_per_second =
- (double)((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->r_frame_rate.num /
- (double)((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->r_frame_rate.den;
- break;
- case CODEC_TYPE_AUDIO:
- //Set stream type to "AUDIO"
- info->stream_type = AC_STREAM_TYPE_AUDIO;
-
- //Store more information about the video stream
- 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;
-
- break;
- default:
- info->stream_type = AC_STREAM_TYPE_UNKNOWN;
- }
+static int64_t io_seek(void *opaque, int64_t pos, int whence)
+{
+ lp_ac_data self = ((lp_ac_data)opaque);
+ if (self->seek_proc != NULL) {
+ if ((whence >= 0) && (whence <= 2)) {
+ return self->seek_proc(self->sender, pos, whence);
+ }
+ }
+ return -1;
+}
+
+lp_ac_proberesult CALL_CONVT ac_probe_input_buffer(uint8_t *buf, int bufsize,
+ char *filename,
+ int *score_max)
+{
+ AVProbeData pd;
+ AVInputFormat *fmt = NULL;
+
+ // Initialize FFMpeg libraries
+ ac_init_ffmpeg();
+
+ // Set the filename and mime_type
+ pd.mime_type = "";
+ pd.filename = "";
+ if (filename) {
+ pd.filename = filename;
+ }
+
+ // The given buffer has to be copied to a new one, which is aligned and
+ // padded
+ uint8_t *aligned_buf = av_malloc(bufsize + AVPROBE_PADDING_SIZE);
+ memset(aligned_buf, 0, bufsize + AVPROBE_PADDING_SIZE);
+ memcpy(aligned_buf, buf, bufsize);
+
+ // Set the probe data buffer
+ pd.buf = aligned_buf;
+ pd.buf_size = bufsize;
+
+ // Test it
+ int score_ret;
+ fmt = av_probe_input_format3(&pd, 1, &score_ret);
+ if (score_ret > *score_max) {
+ *score_max = score_ret;
+ }
+
+ // Free the temporary buffer
+ av_free(aligned_buf);
+
+ return (lp_ac_proberesult)fmt;
+}
+
+AVInputFormat *ac_probe_input_stream(void *sender, ac_read_callback read_proc,
+ char *filename, uint8_t **buf,
+ size_t *buf_read)
+{
+ // Initialize the result variables
+ AVInputFormat *fmt = NULL;
+ *buf_read = 0;
+ *buf = NULL;
+ int last_iteration = 0;
+ int probe_size = 0;
+
+ for (probe_size = PROBE_BUF_MIN;
+ (probe_size <= PROBE_BUF_MAX) && !fmt && !last_iteration;
+ probe_size <<= 1) {
+ int score = AVPROBE_SCORE_MAX / 4;
+
+ // Allocate some memory for the current probe buffer
+ uint8_t *tmp_buf = av_malloc(probe_size);
+ memset(tmp_buf, 0, probe_size);
+
+ // Copy the old data to the new buffer
+ if (*buf) {
+ memcpy(tmp_buf, *buf, *buf_read);
+ // Free the old data memory
+ av_free(*buf);
+ }
+
+ // Read the new data
+ uint8_t *write_ptr = tmp_buf + *buf_read;
+ int read_size = probe_size - (int)*buf_read;
+ int size = read_proc(sender, write_ptr, read_size);
+ if (size < 0) {
+ return fmt; // An error occurred, abort
+ }
+ if (size < read_size) {
+ last_iteration = 1;
+ probe_size = (int)*buf_read + size;
+ }
+
+ // Probe it
+ fmt = (AVInputFormat *)ac_probe_input_buffer(tmp_buf, probe_size,
+ filename, &score);
+
+ // Set the new buffer
+ *buf = tmp_buf;
+ *buf_read = probe_size;
+ }
+
+ // Return the result
+ return fmt;
+}
+
+static void cpymetadata(const AVFormatContext *ctx, const char *key, char *tar,
+ size_t len)
+{
+ const AVDictionaryEntry *entry = av_dict_get(ctx->metadata, key, NULL, 0);
+ if (entry) {
+ strncpy_s(tar, len, entry->value, len);
+ } else {
+ strncpy_s(tar, len, "", len);
+ }
+}
+
+static void cpymetadatai(const AVFormatContext *ctx, const char *key, int *tar)
+{
+ char buf[16];
+ cpymetadata(ctx, key, buf, 16);
+ *tar = atoi(buf);
+}
+
+static int finalize_open(lp_ac_instance pacInstance)
+{
+ lp_ac_data self = ((lp_ac_data)pacInstance);
+
+ // Assume the stream is opened
+ pacInstance->opened = 1;
+
+ // Retrieve stream information
+ AVFormatContext *ctx = self->pFormatCtx;
+ if (avformat_find_stream_info(ctx, NULL) >= 0) {
+ cpymetadata(ctx, "title", pacInstance->info.title, 512);
+ cpymetadata(ctx, "artist", pacInstance->info.author, 512);
+ cpymetadata(ctx, "copyright", pacInstance->info.copyright, 512);
+ cpymetadata(ctx, "comment", pacInstance->info.comment, 512);
+ cpymetadata(ctx, "album", pacInstance->info.album, 512);
+ cpymetadata(ctx, "genre", pacInstance->info.genre, 32);
+ cpymetadatai(ctx, "year", &(pacInstance->info.year));
+ cpymetadatai(ctx, "track", &(pacInstance->info.track));
+ pacInstance->info.bitrate = (int)ctx->bit_rate;
+ pacInstance->info.duration = ctx->duration * 1000 / AV_TIME_BASE;
+ } else {
+ ac_close(pacInstance);
+ return -1;
+ }
+
+ // Set some information in the instance variable
+ pacInstance->stream_count =
+ ((lp_ac_data)pacInstance)->pFormatCtx->nb_streams;
+ if (pacInstance->stream_count <= 0) {
+ ac_close(pacInstance);
+ return -1;
+ }
+ return 0;
+}
+
+int CALL_CONVT ac_open(lp_ac_instance pacInstance, void *sender,
+ ac_openclose_callback open_proc,
+ ac_read_callback read_proc, ac_seek_callback seek_proc,
+ ac_openclose_callback close_proc,
+ lp_ac_proberesult proberesult)
+{
+ // Instance cannot be opened twice!
+ if (pacInstance->opened) {
+ return -1;
+ }
+
+ // Reference at the underlying lp_ac_data instance
+ lp_ac_data self = ((lp_ac_data)pacInstance);
+
+ // Store the given parameters in the ac Instance
+ self->sender = sender;
+ self->open_proc = open_proc;
+ self->read_proc = read_proc;
+ self->seek_proc = seek_proc;
+ self->close_proc = close_proc;
+
+ // Call the file open proc
+ if (self->open_proc != NULL) {
+ if (self->open_proc(sender) < 0) {
+ return -1;
+ }
+ }
+
+ AVInputFormat *fmt = NULL;
+
+ // Probe the input format, if no probe result is specified
+ if (proberesult == NULL) {
+ fmt =
+ ac_probe_input_stream(sender, read_proc, "", &(self->probe_buffer),
+ &(self->probe_buffer_size));
+ } else {
+ fmt = (AVInputFormat *)proberesult;
+ }
+
+ if (!fmt) {
+ ac_close(pacInstance);
+ return -1;
+ }
+
+ // Reserve the buffer memory and initialise the context
+ self->buffer = av_malloc(AC_BUFSIZE);
+ self->pIo = avio_alloc_context(self->buffer, AC_BUFSIZE, 0, self, io_read,
+ 0, seek_proc ? io_seek : NULL);
+ self->pIo->seekable = seek_proc != NULL;
+
+ // Open the given input stream (the io structure) with the given format of
+ // the stream (fmt) and write the pointer to the new format context to the
+ // pFormatCtx variable
+ self->pFormatCtx = avformat_alloc_context();
+ self->pFormatCtx->pb = self->pIo;
+ if (avformat_open_input(&(self->pFormatCtx), "", fmt, NULL) < 0) {
+ ac_close(pacInstance);
+ return -1;
+ }
+
+ return finalize_open(pacInstance);
+}
+
+int CALL_CONVT ac_open_file(lp_ac_instance pacInstance, const char *filename)
+{
+ // Instance cannot be opened twice!
+ if (pacInstance->opened) {
+ return -1;
+ }
+
+ // Reference at the underlying lp_ac_data instance
+ lp_ac_data self = ((lp_ac_data)pacInstance);
+
+ self->pFormatCtx = NULL;
+ if (avformat_open_input(&(self->pFormatCtx), filename, NULL, NULL) < 0) {
+ ac_close(pacInstance);
+ return -1;
+ }
+
+ return finalize_open(pacInstance);
+}
+
+void CALL_CONVT ac_close(lp_ac_instance pacInstance)
+{
+ lp_ac_data self = ((lp_ac_data)pacInstance);
+ if (pacInstance->opened) {
+ // Close the opened file
+ if (self->close_proc != NULL) {
+ self->close_proc(((lp_ac_data)(pacInstance))->sender);
+ }
+
+ avformat_close_input(&(self->pFormatCtx));
+
+ pacInstance->opened = 0;
+ }
+
+ // Make sure all buffers are freed
+ av_free(self->probe_buffer);
+ av_free(self->buffer);
+ av_free(self->pIo);
+ self->buffer = NULL;
+ self->probe_buffer = NULL;
+ self->pIo = NULL;
+ self->pFormatCtx = NULL;
+ self->sender = NULL;
+ self->open_proc = NULL;
+ self->read_proc = NULL;
+ self->seek_proc = NULL;
+ self->close_proc = NULL;
+}
+
+void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb,
+ lp_ac_stream_info info)
+{
+ // Rese the stream info structure
+ memset(info, 0, sizeof(ac_stream_info));
+ info->stream_type = AC_STREAM_TYPE_UNKNOWN;
+
+ // Abort if the instance is not opened
+ if (!(pacInstance->opened)) {
+ return;
+ }
+
+ // Read the information
+ lp_ac_data self = ((lp_ac_data)pacInstance);
+ switch (self->pFormatCtx->streams[nb]->codecpar->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ // Set stream type to "VIDEO"
+ info->stream_type = AC_STREAM_TYPE_VIDEO;
+
+ // Store more information about the video stream
+ info->additional_info.video_info.frame_width =
+ self->pFormatCtx->streams[nb]->codecpar->width;
+ info->additional_info.video_info.frame_height =
+ self->pFormatCtx->streams[nb]->codecpar->height;
+
+ double pixel_aspect_num =
+ self->pFormatCtx->streams[nb]->codecpar->sample_aspect_ratio.num;
+ double pixel_aspect_den =
+ self->pFormatCtx->streams[nb]->codecpar->sample_aspect_ratio.den;
+
+ // Sometime "pixel aspect" may be zero or have other invalid values.
+ // Correct this.
+ if (pixel_aspect_num <= 0.0 || pixel_aspect_den <= 0.0)
+ info->additional_info.video_info.pixel_aspect = 1.0;
+ else
+ info->additional_info.video_info.pixel_aspect = (float)(
+ pixel_aspect_num / pixel_aspect_den);
+
+ info->additional_info.video_info.frames_per_second =
+ (double)self->pFormatCtx->streams[nb]->r_frame_rate.num /
+ (double)self->pFormatCtx->streams[nb]->r_frame_rate.den;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ // Set stream type to "AUDIO"
+ info->stream_type = AC_STREAM_TYPE_AUDIO;
+
+ // Store more information about the video stream
+ info->additional_info.audio_info.samples_per_second =
+ self->pFormatCtx->streams[nb]->codecpar->sample_rate;
+ info->additional_info.audio_info.channel_count =
+ self->pFormatCtx->streams[nb]->codecpar->channels;
+
+ // Set bit depth
+ switch (self->pFormatCtx->streams[nb]->codecpar->format) {
+ // 8-Bit
+ case AV_SAMPLE_FMT_U8:
+ case AV_SAMPLE_FMT_U8P:
+ info->additional_info.audio_info.bit_depth = 8;
+ break;
+
+ // 16-Bit
+ case AV_SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S16P:
+ info->additional_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:
+ case AV_SAMPLE_FMT_DBL:
+ case AV_SAMPLE_FMT_S32P:
+ case AV_SAMPLE_FMT_FLTP:
+ case AV_SAMPLE_FMT_DBLP:
+ info->additional_info.audio_info.bit_depth = 32;
+ break;
+
+ // Unknown format, return zero
+ default:
+ info->additional_info.audio_info.bit_depth = 0;
+ }
+
+ break;
+ default: {
+ // Do nothing
+ }
+ }
}
//
//---Package management---
//
-lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance) {
- //Try to read package
- AVPacket Package;
- if (av_read_frame(((lp_ac_data)(pacInstance))->pFormatCtx, &Package) >= 0) {
- //Reserve memory
- lp_ac_package_data pTmp = (lp_ac_package_data)(av_malloc(sizeof(ac_package_data)));
- memset(pTmp, 0, sizeof(ac_package_data));
-
- //Set package data
- pTmp->package.stream_index = Package.stream_index;
- pTmp->ffpackage = Package;
-
- if (Package.dts != AV_NOPTS_VALUE) {
- pTmp->pts = Package.dts;
- }
-
- return (lp_ac_package)(pTmp);
- } else {
+lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance)
+{
+ // Allocate the result packet
+ lp_ac_package_data pkt = av_malloc(sizeof(ac_package_data));
+ memset(pkt, 0, sizeof(ac_package_data));
+ pkt->pPack = av_malloc(sizeof(AVPacket));
+
+ av_init_packet(pkt->pPack);
+ pkt->pPack->data = NULL;
+ pkt->pPack->size = 0;
+
+ // Try to read package
+ if (av_read_frame(((lp_ac_data)(pacInstance))->pFormatCtx, pkt->pPack) >=
+ 0) {
+ if (pkt->pPack->dts != AV_NOPTS_VALUE) {
+ pkt->pts = (int)pkt->pPack->dts;
+ }
+ pkt->package.stream_index = pkt->pPack->stream_index;
+ return (lp_ac_package)(pkt);
+ }
+ ac_free_package((lp_ac_package)pkt);
return NULL;
- }
}
-//Frees the currently loaded package
+// Frees the currently loaded package
void CALL_CONVT ac_free_package(lp_ac_package pPackage)
{
- //Free the packet
- if (pPackage != NULL) {
- AVPacket* pkt = &((lp_ac_package_data)pPackage)->ffpackage;
- if (pkt) {
- if (pkt->destruct){pkt->destruct = av_destruct_packet; pkt->destruct(pkt);} //FIXME: workaround for deprecation of AVPacket::destruct
- pkt->data = NULL; pkt->size = 0;
- }
- av_free((lp_ac_package_data)pPackage);
- }
+ if (pPackage) {
+ lp_ac_package_data self = (lp_ac_package_data)pPackage;
+ if (self->pPack) {
+ if (self->pPack->buf) {
+ av_buffer_unref(&self->pPack->buf);
+ }
+ self->pPack->data = NULL;
+ self->pPack->size = 0;
+
+ av_packet_free_side_data(self->pPack);
+ }
+ av_free(self->pPack);
+ av_free(self);
+ }
}
//
//--- Decoder management ---
//
-enum PixelFormat convert_pix_format(ac_output_format fmt) {
- switch (fmt) {
- case AC_OUTPUT_RGB24: return PIX_FMT_RGB24;
- case AC_OUTPUT_BGR24: return PIX_FMT_BGR24;
- case AC_OUTPUT_RGBA32: return PIX_FMT_RGB32;
- case AC_OUTPUT_BGRA32: return PIX_FMT_BGR32;
- }
- return PIX_FMT_RGB32;
-}
-
-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;
- 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)
+enum AVPixelFormat convert_pix_format(ac_output_format fmt)
{
- //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);
-
- //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;
-
- return (void*)pDecoder;
-}
-
-double ac_sync_video(lp_ac_package pPackage, lp_ac_decoder pDec, AVFrame *src_frame, double pts){
- double frame_delay;
-
- if(pts != 0){
- pDec->video_clock = pts;
- } else {
- pts = pDec->video_clock;
- }
-
- frame_delay = av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base);
- frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
- pDec->video_clock += frame_delay;
- return pts;
-}
-
-int ac_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder, lp_ac_decoder pDec)
-{
- int finished = 0;
- double pts = 0;
- int len = 0;
-
- AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage;
-
- while (pkt_tmp.size > 0) {
- len = avcodec_decode_video2(
- pDecoder->pCodecCtx, pDecoder->pFrame,
- &finished, &pkt_tmp);
-
- if (len < 0) {
- return 0;
+ switch (fmt) {
+ case AC_OUTPUT_RGB24:
+ return AV_PIX_FMT_RGB24;
+ case AC_OUTPUT_BGR24:
+ return AV_PIX_FMT_BGR24;
+ case AC_OUTPUT_RGBA32:
+ return AV_PIX_FMT_RGB32;
+ case AC_OUTPUT_BGRA32:
+ return AV_PIX_FMT_BGR32;
+ case AC_OUTPUT_YUV420P:
+ return AV_PIX_FMT_YUV420P;
+ case AC_OUTPUT_UYVY422:
+ return AV_PIX_FMT_UYVY422;
+ case AC_OUTPUT_YUYV422:
+ return AV_PIX_FMT_YUYV422;
}
+ return AV_PIX_FMT_RGB24;
+}
- pkt_tmp.size -= len;
- pkt_tmp.data += len;
- }
+// 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));
+
+ // Set a few properties
+ pDecoder->decoder.pacInstance = pacInstance;
+ pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO;
+ pDecoder->decoder.stream_index = nb;
- if (finished != 0) {
- pDecoder->pSwsCtx = sws_getCachedContext(pDecoder->pSwsCtx,
- pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt,
- pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, convert_pix_format(pDecoder->decoder.pacInstance->output_format),
- SWS_FAST_BILINEAR, NULL, NULL, NULL);
-
- sws_scale(
- pDecoder->pSwsCtx,
- (const uint8_t* const*)(pDecoder->pFrame->data),
- pDecoder->pFrame->linesize,
- 0, //?
- pDecoder->pCodecCtx->height,
- pDecoder->pFrameRGB->data,
- pDecoder->pFrameRGB->linesize);
-
-
- if(pkt_tmp.dts == AV_NOPTS_VALUE &&
- *(uint64_t*)pDecoder->pFrame->opaque != AV_NOPTS_VALUE ){
- pts = *(uint64_t*)pDecoder->pFrame->opaque;
- } else if(pkt_tmp.dts != AV_NOPTS_VALUE){
- pts = pkt_tmp.dts;
+ AVCodecParameters* pCodecParam = ((lp_ac_data)(pacInstance))->pFormatCtx->streams[nb]->codecpar;
+ pDecoder->decoder.stream_info = *info;
+
+ // Find correspondenting codec
+ if (!(pDecoder->pCodec =
+ avcodec_find_decoder(pCodecParam->codec_id))) {
+ return NULL; // Codec could not have been found
}
-
- if(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time != AV_NOPTS_VALUE){
- pts -= ((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time;
- }
- pts *= av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base);
-
- pts = ac_sync_video(pPackage, pDec, pDecoder->pFrame, pts);
- pDec->timecode = pts;
-
- return 1;
- }
- return 0;
+ pDecoder->pCodecCtx = avcodec_alloc_context3(pDecoder->pCodec);
+ avcodec_parameters_to_context(pDecoder->pCodecCtx, pCodecParam);
+
+ // Open codec
+ if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) {
+ return NULL; // Codec could not have been opened
+ }
+
+ // Reserve frame variables
+ pDecoder->pFrame = av_frame_alloc();
+ pDecoder->pFrameRGB = av_frame_alloc();
+
+ pDecoder->pSwsCtx = NULL;
+
+ // Reserve buffer memory
+ pDecoder->decoder.buffer_size = av_image_get_buffer_size(
+ convert_pix_format(pacInstance->output_format),
+ pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height,
+ 1);
+ pDecoder->decoder.pBuffer =
+ (uint8_t *)av_malloc(pDecoder->decoder.buffer_size);
+
+ // Link decoder to buffer
+ av_image_fill_arrays(pDecoder->pFrameRGB->data,
+ pDecoder->pFrameRGB->linesize,
+ pDecoder->decoder.pBuffer,
+ convert_pix_format(pacInstance->output_format),
+ pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height,
+ 1);
+
+ return (void *)pDecoder;
}
-int alloc_samples_array_and_data(uint8_t ***data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align)
+// Init a audio decoder
+void *ac_create_audio_decoder(lp_ac_instance pacInstance,
+ lp_ac_stream_info info, int nb)
{
- int nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1;
+ // Allocate memory for a new decoder instance
+ lp_ac_data self = ((lp_ac_data)(pacInstance));
+ lp_ac_audio_decoder pDecoder = NULL;
+ ERR(pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder))));
+ memset(pDecoder, 0, sizeof(ac_audio_decoder));
- *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);
-}
+ // 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;
+
+ AVCodecParameters* pCodecParam = self->pFormatCtx->streams[nb]->codecpar;
-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
- int dest_buffer_pos = pDecoder->decoder.buffer_size;
-
- //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;
+ // Find correspondenting codec
+ ERR(pDecoder->pCodec = avcodec_find_decoder(pCodecParam->codec_id));
- while (pkt_tmp.size > 0) {
-
- if (!decoded_frame) {
- if (!(decoded_frame = avcodec_alloc_frame())) {
- return 0;
+ pDecoder->pCodecCtx = avcodec_alloc_context3(pDecoder->pCodec);
+ avcodec_parameters_to_context(pDecoder->pCodecCtx, pCodecParam);
+
+ // Open codec
+ AV_ERR(avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL));
+
+ // Initialize the buffers
+ pDecoder->decoder.pBuffer = NULL; // av_malloc(AUDIO_BUFFER_BASE_SIZE);
+ pDecoder->decoder.buffer_size = 0;
+ ERR(pDecoder->pFrame = av_frame_alloc());
+
+ // Fetch audio format, rate and channel layout -- under some circumstances,
+ // the layout is not known to the decoder, then a channel layout is guessed
+ // from the channel count.
+ const enum AVSampleFormat fmt = pDecoder->pCodecCtx->sample_fmt;
+ const int rate = pDecoder->pCodecCtx->sample_rate;
+ const int64_t layout =
+ pDecoder->pCodecCtx->channel_layout
+ ? pDecoder->pCodecCtx->channel_layout
+ : av_get_default_channel_layout(pDecoder->pCodecCtx->channels);
+
+ // Initialize libswresample if needed
+ if (av_sample_fmt_is_planar(fmt) || (fmt == AV_SAMPLE_FMT_S32) ||
+ (fmt == AV_SAMPLE_FMT_DBL)) {
+ enum AVSampleFormat out_fmt = av_get_packed_sample_fmt(fmt);
+ if (out_fmt == AV_SAMPLE_FMT_DBL || out_fmt == AV_SAMPLE_FMT_S32) {
+ out_fmt = AV_SAMPLE_FMT_FLT;
}
- } else
- avcodec_get_frame_defaults(decoded_frame);
-
- int got_frame = 0;
-
- 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;
+ pDecoder->pSwrCtx = swr_alloc_set_opts(NULL, layout, out_fmt, rate,
+ layout, fmt, rate, 0, NULL);
+ AV_ERR(swr_init(pDecoder->pSwrCtx));
}
-
- //Increment the source buffer pointers
- pkt_tmp.size -= len1;
- pkt_tmp.data += len1;
+ return (void *)pDecoder;
+
+error:
+ ac_free_audio_decoder(pDecoder);
+ return NULL;
+}
+
+lp_ac_decoder CALL_CONVT ac_create_decoder(lp_ac_instance pacInstance, int nb)
+{
+ // Get information about the chosen data stream and create an decoder that
+ // can handle this kind of stream.
+ ac_stream_info info;
+ ac_get_stream_info(pacInstance, nb, &info);
+
+ lp_ac_decoder_data result = NULL;
+
+ if (info.stream_type == AC_STREAM_TYPE_VIDEO) {
+ result =
+ (lp_ac_decoder_data)ac_create_video_decoder(pacInstance, &info, nb);
+ } else if (info.stream_type == AC_STREAM_TYPE_AUDIO) {
+ result =
+ (lp_ac_decoder_data)ac_create_audio_decoder(pacInstance, &info, nb);
+ }
+
+ if (result) {
+ result->decoder.timecode = 0;
+ result->last_timecode = 0;
+ result->sought = 1;
+ }
+
+ return (lp_ac_decoder)result;
+}
+
+int ac_decode_video_package(lp_ac_package pPackage,
+ lp_ac_video_decoder pDecoder)
+{
+ lp_ac_package_data pkt = ((lp_ac_package_data)pPackage);
+
+ if(avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0)
+ {
+ return 0;
+ }
+
+ if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0)
+ {
+ return 0;
+ }
+
+ pDecoder->pSwsCtx = sws_getCachedContext(
+ pDecoder->pSwsCtx, pDecoder->pCodecCtx->width,
+ pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt,
+ pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height,
+ convert_pix_format(pDecoder->decoder.pacInstance->output_format),
+ SWS_BICUBIC, NULL, NULL, NULL);
+
+ sws_scale(pDecoder->pSwsCtx,
+ (const uint8_t *const *)(pDecoder->pFrame->data),
+ pDecoder->pFrame->linesize,
+ 0, //?
+ pDecoder->pCodecCtx->height, pDecoder->pFrameRGB->data,
+ pDecoder->pFrameRGB->linesize);
+ return 1;
- 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;
+int ac_skip_video_package(lp_ac_package pPackage,
+ lp_ac_video_decoder pDecoder)
+{
+ lp_ac_package_data pkt = ((lp_ac_package_data)pPackage);
- /* 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 (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0)
+ {
+ return 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 = 4 * pDec->stream_info.audio_info.samples_per_second;
- if (bytes_per_second > 0)
- pDec->video_clock += data_size / bytes_per_second;
-
- pDec->timecode = pts;
-
- if (dst_data)
- av_freep(&dst_data[0]);
- av_freep(&dst_data);
+ if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0)
+ {
+ return 0;
+ }
+
+ return 1;
+}
- swr_free(&swr_ctx);
- return 1;
- }
- }
-
- return 0;
+int ac_decode_audio_package(lp_ac_package pPackage,
+ lp_ac_audio_decoder pDecoder)
+{
+ int got_frame = 0;
+ int len = 0;
+ lp_ac_package_data pkt = ((lp_ac_package_data)pPackage);
+
+ if (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0)
+ {
+ return 0;
+ }
+
+ if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0)
+ {
+ return 0;
+ }
+
+ // Calculate the output buffer size
+ const int sample_size =
+ MIN(4, av_get_bytes_per_sample(pDecoder->pCodecCtx->sample_fmt));
+ const int sample_count = pDecoder->pFrame->nb_samples;
+ const int channel_count = pDecoder->pFrame->channels;
+ const int buffer_size = sample_size * sample_count * channel_count;
+ pDecoder->decoder.buffer_size = buffer_size;
+
+ if (pDecoder->pSwrCtx) {
+ if (pDecoder->own_buffer_size != buffer_size) {
+ pDecoder->decoder.pBuffer =
+ av_realloc(pDecoder->decoder.pBuffer, buffer_size);
+ pDecoder->own_buffer_size = buffer_size;
+ }
+ swr_convert(pDecoder->pSwrCtx, &(pDecoder->decoder.pBuffer),
+ sample_count, (const uint8_t **)(pDecoder->pFrame->data),
+ sample_count);
+ } else {
+ // No conversion needs to be done, simply set the buffer pointer
+ pDecoder->decoder.pBuffer = pDecoder->pFrame->data[0];
+ }
+
+ return got_frame;
+}
+
+int ac_skip_audio_package(lp_ac_package pPackage,
+ lp_ac_audio_decoder pDecoder)
+{
+ int got_frame = 0;
+ int len = 0;
+ lp_ac_package_data pkt = ((lp_ac_package_data)pPackage);
+ if (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0)
+ {
+ return 0;
+ }
+
+ if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0)
+ {
+ return 0;
+ }
+
+ return got_frame;
}
int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder)
{
- if (pDecoder->type == AC_DECODER_TYPE_AUDIO)
- return ac_decode_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder, pDecoder);
- else if (pDecoder->type == AC_DECODER_TYPE_VIDEO)
- return ac_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder, pDecoder);
+ double timebase = av_q2d(((lp_ac_data)pDecoder->pacInstance)
+ ->pFormatCtx->streams[pPackage->stream_index]
+ ->time_base);
- return 0;
-}
+ // Create a valid timecode
+ if (((lp_ac_package_data)pPackage)->pts > 0) {
+ lp_ac_decoder_data dec_dat = (lp_ac_decoder_data)pDecoder;
-int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder)
-{
- if (pDecoder->type == AC_DECODER_TYPE_VIDEO) {
- return ac_drop_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder, pDecoder);
- }
- return 0;
-}
+ dec_dat->last_timecode = pDecoder->timecode;
+ pDecoder->timecode = ((lp_ac_package_data)pPackage)->pts * timebase;
-int ac_drop_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder, lp_ac_decoder pDec) {
- int finished;
- double pts;
- int len = 0;
+ double delta = pDecoder->timecode - dec_dat->last_timecode;
+ double max_delta, min_delta;
- AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage;
-
- while (pkt_tmp.size > 0) {
- len = avcodec_decode_video2(
- pDecoder->pCodecCtx, pDecoder->pFrame,
- &finished, &pkt_tmp);
-
- if (len < 0) {
- return 0;
+ if (dec_dat->sought > 0) {
+ max_delta = 120.0;
+ min_delta = -120.0;
+ --dec_dat->sought;
+ } else {
+ max_delta = 4.0;
+ min_delta = 0.0;
+ }
+
+ if ((delta < min_delta) || (delta > max_delta)) {
+ pDecoder->timecode = dec_dat->last_timecode;
+ if (dec_dat->sought > 0) {
+ ++dec_dat->sought;
+ }
+ }
}
- pkt_tmp.size -= len;
- pkt_tmp.data += len;
- }
-
- if (finished) {
- pts=0;
-
- if(((lp_ac_package_data)pPackage)->ffpackage.dts == AV_NOPTS_VALUE &&
- *(uint64_t*)pDecoder->pFrame->opaque != AV_NOPTS_VALUE ){
- pts = *(uint64_t*)pDecoder->pFrame->opaque;
- } else if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){
- pts = ((lp_ac_package_data)pPackage)->ffpackage.dts;
- } else {
- pts = 0;
+ if (pDecoder->type == AC_DECODER_TYPE_VIDEO) {
+ return ac_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder);
+ } else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) {
+ return ac_decode_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder);
}
-
- if(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time != AV_NOPTS_VALUE){
- pts -= ((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time;
- }
-
- pts *= av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base);
-
- pts = ac_sync_video(pPackage, pDec, pDecoder->pFrame, pts);
- pDec->timecode = pts;
-
- return 1;
- }
- return 0;
+ return 0;
}
-int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder)
+int CALL_CONVT ac_skip_package(lp_ac_package pPackage, lp_ac_decoder pDecoder)
{
- lp_ac_package pPackage = ac_read_package(pacInstance);
- ((lp_ac_audio_decoder)pDecoder)->decoder.buffer_size = 0;
-
- int done = 0;
- 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 (done == 0)
- pPackage = ac_read_package(pacInstance);
- } else {
- ac_free_package(pPackage);
- pPackage = ac_read_package(pacInstance);
- }
- }
-
- if (done == 0)
- return 0;
- else
- return 1;
-}
+ double timebase = av_q2d(((lp_ac_data)pDecoder->pacInstance)
+ ->pFormatCtx->streams[pPackage->stream_index]
+ ->time_base);
-int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder)
-{
- lp_ac_package pPackage = ac_read_package(pacInstance);
- int done = 0;
- int pcount = 0;
- 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);
- pcount++;
- if (done == 0)
- pPackage = ac_read_package(pacInstance);
- } else
- {
- ac_free_package(pPackage);
- pPackage = ac_read_package(pacInstance);
- }
- }
+ // Create a valid timecode
+ if (((lp_ac_package_data)pPackage)->pts > 0) {
+ lp_ac_decoder_data dec_dat = (lp_ac_decoder_data)pDecoder;
- if (done == 0)
- return 0;
- else
- return pcount;
+ dec_dat->last_timecode = pDecoder->timecode;
+ pDecoder->timecode = ((lp_ac_package_data)pPackage)->pts * timebase;
+
+ double delta = pDecoder->timecode - dec_dat->last_timecode;
+ double max_delta, min_delta;
+
+ if (dec_dat->sought > 0) {
+ max_delta = 120.0;
+ min_delta = -120.0;
+ --dec_dat->sought;
+ }
+ else {
+ max_delta = 4.0;
+ min_delta = 0.0;
+ }
+
+ if ((delta < min_delta) || (delta > max_delta)) {
+ pDecoder->timecode = dec_dat->last_timecode;
+ if (dec_dat->sought > 0) {
+ ++dec_dat->sought;
+ }
+ }
+ }
+
+ if (pDecoder->type == AC_DECODER_TYPE_VIDEO) {
+ return ac_skip_video_package(pPackage, (lp_ac_video_decoder)pDecoder);
+ }
+ else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) {
+ return ac_skip_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder);
+ }
+ return 0;
}
int CALL_CONVT ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num)
{
- lp_ac_package pPackage = ac_read_package(pacInstance);
-
- int done = 0;
- int i;
- for(i=0; i0)
- pPackage = ac_read_package(pacInstance);
-
- done = 0;
- while(done == 0 && pPackage != NULL){
- if (((lp_ac_package_data)pPackage)->package.stream_index == pDecoder->stream_index)
- {
- done = ac_drop_decode_package(pPackage, pDecoder);
- ac_free_package(pPackage);
-
- if (done == 0)
- pPackage = ac_read_package(pacInstance);
- } else
- {
- ac_free_package(pPackage);
- pPackage = ac_read_package(pacInstance);
- }
- }
-
- if (done == 0)
- return 0;
- }
-
- if (done == 0)
- return 0;
- else
- return 1;
+ if (pDecoder == NULL)
+ {
+ return 0;
+ }
+
+ int skipedFrames = 0;
+
+ while (skipedFrames < num)
+ {
+ lp_ac_package pckt = ac_read_package(pacInstance);
+ if (pckt != NULL)
+ {
+ // Decode the package to figure out if its completing a frame
+ if (pckt->stream_index == pDecoder->stream_index && ac_skip_package(pckt, pDecoder) != 0)
+ {
+ skipedFrames++;
+ }
+
+ ac_free_package(pckt);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ return 1;
}
-//Seek function
+int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder)
+{
+ if (pDecoder == NULL)
+ {
+ return 0;
+ }
+
+ do
+ {
+ lp_ac_package pckt = ac_read_package(pacInstance);
+ if (pckt == NULL)
+ {
+ return 0;
+ }
+
+ if(pckt->stream_index != pDecoder->stream_index)
+ {
+ continue;
+ }
+
+ // The packet is for the video stream, try to decode it
+ if (ac_decode_package(pckt, pDecoder) != 0)
+ {
+ ac_free_package(pckt);
+ return 1;
+ }
+
+ ac_free_package(pckt);
+
+ } while (true);
+}
+
+int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder)
+{
+ if (pDecoder == NULL)
+ {
+ return 0;
+ }
+
+ do
+ {
+ lp_ac_package pckt = ac_read_package(pacInstance);
+ if (pckt == NULL)
+ {
+ return 0;
+ }
+
+ if (pckt->stream_index != pDecoder->stream_index)
+ {
+ continue;
+ }
+
+ // The packet is for the audio stream, try to decode it
+ if (ac_decode_package(pckt, pDecoder) != 0)
+ {
+ ac_free_package(pckt);
+ return 1;
+ }
+
+ ac_free_package(pckt);
+
+ } while (true);
+}
+
+// Seek function
int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos)
{
- AVRational timebase = ((lp_ac_data)pDecoder->pacInstance)->pFormatCtx->streams[pDecoder->stream_index]->time_base;
- int flags = dir < 0 ? AVSEEK_FLAG_BACKWARD : 0;
- int64_t pos = av_rescale(target_pos, AV_TIME_BASE, 1000);
- pDecoder->timecode = target_pos / 1000.0;
- pDecoder->video_clock = target_pos / 1000.0;
-
- if (av_seek_frame(((lp_ac_data)pDecoder->pacInstance)->pFormatCtx, pDecoder->stream_index,
- av_rescale_q(pos, AV_TIME_BASE_Q, timebase), flags) >= 0)
- {
-
- if (pDecoder->type == AC_DECODER_TYPE_AUDIO)
- {
- if (((lp_ac_audio_decoder)pDecoder)->pCodecCtx->codec->flush != NULL)
- avcodec_flush_buffers(((lp_ac_audio_decoder)pDecoder)->pCodecCtx);
- }
-
- if (pDecoder->type == AC_DECODER_TYPE_VIDEO)
- {
- if (((lp_ac_video_decoder)pDecoder)->pCodecCtx->codec->flush != NULL)
- avcodec_flush_buffers(((lp_ac_video_decoder)pDecoder)->pCodecCtx);
- }
- return 1;
- }
- return 0;
+ AVRational timebase = ((lp_ac_data)pDecoder->pacInstance)
+ ->pFormatCtx->streams[pDecoder->stream_index]
+ ->time_base;
+
+ int flags = dir < 0 ? AVSEEK_FLAG_BACKWARD : 0;
+
+ int64_t pos = av_rescale(target_pos, AV_TIME_BASE, 1000);
+
+ ((lp_ac_decoder_data)pDecoder)->sought = 100;
+ pDecoder->timecode = (double)target_pos / 1000;
+
+ if (av_seek_frame(((lp_ac_data)pDecoder->pacInstance)->pFormatCtx,
+ pDecoder->stream_index,
+ av_rescale_q(pos, AV_TIME_BASE_Q, timebase),
+ flags) >= 0) {
+ return 1;
+ }
+
+ return 0;
}
-//Free video decoder
+// Free video decoder
void ac_free_video_decoder(lp_ac_video_decoder pDecoder)
-{
- av_free(pDecoder->pFrame);
- av_free(pDecoder->pFrameRGB);
-
- if (pDecoder->pSwsCtx != NULL)
- sws_freeContext(pDecoder->pSwsCtx);
-
- avcodec_close(pDecoder->pCodecCtx);
-
- //Free reserved memory for the buffer
- av_free(pDecoder->decoder.pBuffer);
-
- //Free reserved memory for decoder record
- av_free(pDecoder);
+{
+ if (pDecoder) {
+ av_free(pDecoder->pFrame);
+ av_free(pDecoder->pFrameRGB);
+ sws_freeContext(pDecoder->pSwsCtx);
+ avcodec_free_context(&pDecoder->pCodecCtx);
+ av_free(pDecoder->decoder.pBuffer);
+ av_free(pDecoder);
+ }
}
-//Free video decoder
+// Free video decoder
void ac_free_audio_decoder(lp_ac_audio_decoder pDecoder)
{
- avcodec_close(pDecoder->pCodecCtx);
-
- //Free reserved memory for the buffer
- av_free(pDecoder->decoder.pBuffer);
-
- //Free reserved memory for decoder record
- av_free(pDecoder);
+ if (pDecoder) {
+ avcodec_free_context(&pDecoder->pCodecCtx);
+ av_frame_free(&(pDecoder->pFrame));
+ if (pDecoder->pSwrCtx) {
+ swr_free(&(pDecoder->pSwrCtx));
+ }
+ if (pDecoder->own_buffer_size > 0) {
+ av_free(pDecoder->decoder.pBuffer);
+ }
+ av_free(pDecoder);
+ }
}
void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder)
{
- if (pDecoder->type == AC_DECODER_TYPE_VIDEO)
- ac_free_video_decoder((lp_ac_video_decoder)pDecoder);
- else if (pDecoder->type == AC_DECODER_TYPE_AUDIO)
- ac_free_audio_decoder((lp_ac_audio_decoder)pDecoder);
+ if (pDecoder) {
+ if (pDecoder->type == AC_DECODER_TYPE_VIDEO) {
+ ac_free_video_decoder((lp_ac_video_decoder)pDecoder);
+ } else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) {
+ ac_free_audio_decoder((lp_ac_audio_decoder)pDecoder);
+ }
+ }
}
+
diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.h b/Vocaluxe/Lib/Video/Acinerella/acinerella.h
index bdae2056..a7a228b9 100644
--- a/Vocaluxe/Lib/Video/Acinerella/acinerella.h
+++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.h
@@ -15,8 +15,8 @@
along with Acinerella. If not, see .
*/
-#ifndef VIDEOPLAY_H
-#define VIDEOPLAY_H
+#ifndef _ACINERELLA_H_
+#define _ACINERELLA_H_
#include
#include
@@ -24,187 +24,495 @@
#ifdef _WIN32
#define CALL_CONVT __cdecl
+#define EXTERN extern __declspec(dllexport)
#else
-#define CALL_CONVT
+#define CALL_CONVT
+#define EXTERN extern
#endif
-typedef long long int64;
+/**
+ * Defines the type of an Acinerella media stream. Currently only video and
+ * audio streams are supported, subtitle and data streams will be marked as
+ * "unknown".
+ */
+typedef enum _ac_stream_type {
+ /**
+ * The type of the media stream is not known. This kind of stream can not be
+ * decoded.
+ */
+ AC_STREAM_TYPE_VIDEO = 0,
-/*Defines the type of an Acinerella media stream. Currently only video and
- audio streams are supported, subtitle and data streams will be marked as
- "unknown".*/
-enum _ac_stream_type {
- /*The type of the media stream is not known. This kind of stream can not be
- decoded.*/
- AC_STREAM_TYPE_VIDEO = 0,
- /*This media stream is a video stream.*/
- AC_STREAM_TYPE_AUDIO = 1,
- /*This media stream is an audio stream.*/
- AC_STREAM_TYPE_UNKNOWN = -1
-};
+ /**
+ * This media stream is a video stream.
+ */
+ AC_STREAM_TYPE_AUDIO = 1,
-typedef enum _ac_stream_type ac_stream_type;
+ /**
+ * This media stream is an audio stream.
+ */
+ AC_STREAM_TYPE_UNKNOWN = -1
+} ac_stream_type;
-/*Defines the type of an Acinerella media decoder.*/
-enum _ac_decoder_type {
- /*This decoder is used to decode a video stream.*/
- AC_DECODER_TYPE_VIDEO = 0,
- /* This decoder is used to decode an audio stram.*/
- AC_DECODER_TYPE_AUDIO = 1
-};
+/**
+ * Defines the type of an Acinerella media decoder.
+ */
+typedef enum _ac_decoder_type {
+ /**
+ * This decoder is used to decode a video stream.
+ */
+ AC_DECODER_TYPE_VIDEO = 0,
-typedef enum _ac_decoder_type ac_decoder_type;
+ /**
+ * This decoder is used to decode an audio stram.
+ */
+ AC_DECODER_TYPE_AUDIO = 1
+} ac_decoder_type;
-/*Defines the format video/image data is outputted in*/
-enum _ac_output_format {
- AC_OUTPUT_RGB24 = 0,
- AC_OUTPUT_BGR24 = 1,
- AC_OUTPUT_RGBA32 = 2,
- AC_OUTPUT_BGRA32 = 3
-};
+/**
+ * Defines the format video/image data is returned in.
+ */
+typedef enum _ac_output_format {
+ AC_OUTPUT_RGB24 = 0,
+ AC_OUTPUT_BGR24 = 1,
+ AC_OUTPUT_RGBA32 = 2,
+ AC_OUTPUT_BGRA32 = 3,
+ AC_OUTPUT_YUV420P = 4,
+ AC_OUTPUT_UYVY422 = 5,
+ AC_OUTPUT_YUYV422 = 6
+} ac_output_format;
-typedef enum _ac_output_format ac_output_format;
-
-/*Contains information about the whole file/stream that has been opened. Default values are ""
+/*Contains information about the whole file/stream that has been opened. Default
+values are ""
for strings and -1 for integer values.*/
-struct _ac_file_info {
- /*Length of the file*/
- int64_t duration;
-};
+typedef struct _ac_file_info {
+ /**
+ * Title of the media file
+ */
+ char title[512];
-typedef struct _ac_file_info ac_file_info;
-typedef ac_file_info* lp_ac_file_info;
+ /**
+ * Author or artist of the media file.
+ */
+ char author[512];
-/*TAc_instance represents an Acinerella instance. Each instance can open and
- decode one file at once. There can be only 26 Acinerella instances opened at
- once.*/
-struct _ac_instance {
- /*If true, the instance currently opened a media file.*/
- bool opened;
- /*Contains the count of streams the media file has. This value is available
- after calling the ac_open function.*/
- int stream_count;
- /*Set this value to change the image output format */
- ac_output_format output_format;
- /*Contains information about the opened stream/file*/
- ac_file_info info;
-};
+ /**
+ * Copyright information.
+ */
+ char copyright[512];
-typedef struct _ac_instance ac_instance;
-/*Pointer on the Acinerella instance record.*/
-typedef ac_instance* lp_ac_instance;
+ /**
+ * Comment stored in the file.
+ */
+ char comment[512];
-/*Contains information about an Acinerella video stream.*/
+ /**
+ * Album the media file is from.
+ */
+ char album[512];
+
+ /**
+ * Year in which the media file was created.
+ */
+ int year;
+
+ /**
+ * Track number.
+ */
+ int track;
+
+ /**
+ * Genre of the media file.
+ */
+ char genre[32];
+
+ /**
+ * Length of the file in milliseconds.
+ */
+ int64_t duration;
+
+ /**
+ * Bitrate of the file.
+ */
+ int bitrate;
+} ac_file_info;
+
+typedef ac_file_info *lp_ac_file_info;
+
+/**
+ * ac_instance represents an Acinerella instance. Each instance can open and
+ * decode one file at once.
+ */
+typedef struct _ac_instance {
+ /**
+ * If true, the instance currently opened a media file.
+ */
+ bool opened;
+
+ /**
+ * Contains the count of streams the media file has. This value is available
+ * after calling the ac_open function.
+ */
+ int stream_count;
+
+ /**
+ * Set this value to change the image output format
+ */
+ ac_output_format output_format;
+
+ /**
+ * Contains information about the opened stream/file
+ */
+ ac_file_info info;
+} ac_instance;
+
+/**
+ * Pointer on the Acinerella instance record.
+ */
+typedef ac_instance *lp_ac_instance;
+
+/**
+ * Contains information about an Acinerella video stream.
+ */
struct _ac_video_stream_info {
- /*The width of one frame.*/
- int frame_width;
- /*The height of one frame.*/
- int frame_height;
- /*The width of one pixel. 1.07 for 4:3 format, 1,42 for the 16:9 format*/
- float pixel_aspect;
- /*Frames per second that should be played.*/
- double frames_per_second;
-};
-typedef struct _ac_video_stream_info ac_video_stream_info;
-/*Contains information about an Acinerella audio stream.*/
-struct _ac_audio_stream_info {
- /*Samples per second. Default values are 44100 or 48000.*/
- int samples_per_second;
- /*Bits per sample. Can be 8 or 16 Bit.*/
- int bit_depth;
- /*Count of channels in the audio stream.*/
- int channel_count;
-};
-typedef struct _ac_audio_stream_info ac_audio_stream_info;
+ /**
+ * The width of one frame.
+ */
+ int frame_width;
+ /**
+ * The height of one frame.
+ */
+ int frame_height;
+
+ /**
+ * The width of one pixel. 1.07 for 4:3 format, 1,42 for the 16:9 format
+ */
+ float pixel_aspect;
+
+ /**
+ * Frames per second that should be played.
+ */
+ double frames_per_second;
+};
+
+/**
+ * Contains information about an Acinerella audio stream.
+ */
+struct _ac_audio_stream_info {
+ /**
+ * Samples per second. Default values are 44100 or 48000.
+ */
+ int samples_per_second;
+
+ /**
+ * Bits per sample. Can be 8, 16 or 32 Bit. In the latter case the data is
+ * in floating point format.
+ */
+ int bit_depth;
+
+ /**
+ * Count of channels in the audio stream.
+ */
+ int channel_count;
+};
+
+/**
+ * Additional info about the stream - use "video_info" when the stream
+ * is an video stream, "audio_info" when the stream is an audio stream.
+ */
+union _ac_additional_stream_info {
+ struct _ac_audio_stream_info audio_info;
+ struct _ac_video_stream_info video_info;
+};
/*Contains information about an Acinerella stream.*/
-struct _ac_stream_info {
- /*Contains the type of the stream.*/
- ac_stream_type stream_type;
- ac_audio_stream_info audio_info;
- ac_video_stream_info video_info;
-};
+typedef struct _ac_stream_info {
+ /**
+ * Contains the type of the stream.
+ */
+ ac_stream_type stream_type;
-typedef struct _ac_stream_info ac_stream_info;
-/*Pointer on TAc_stream_info*/
-typedef ac_stream_info* lp_ac_stream_info;
+ /**
+ * Additional data depending on the stream type. Either access the
+ * "audio_info" or the "video_info" field, depending on the value stored in
+ * the "stream_type" member.
+ */
+ union _ac_additional_stream_info additional_info;
+} ac_stream_info;
-/*Contains information about an Acinerella video/audio decoder.*/
-struct _ac_decoder {
- /*Pointer on the Acinerella instance*/
- lp_ac_instance pacInstance;
- /*Contains the type of the decoder.*/
- ac_decoder_type type;
-
- /*The timecode of the currently decoded picture in seconds */
- double timecode;
-
- double video_clock;
-
- /*Contains information about the stream the decoder is attached to.*/
- ac_stream_info stream_info;
- /*The index of the stream the decoder is attached to.*/
- int stream_index;
-
- /*Pointer to the buffer which contains the data.*/
- char *pBuffer;
- /*Size of the data in the buffer.*/
- int buffer_size;
-};
+/**
+ * Pointer on ac_stream_info
+ */
+typedef ac_stream_info *lp_ac_stream_info;
-typedef struct _ac_decoder ac_decoder;
-/*Pointer on TAc_decoder.*/
-typedef ac_decoder* lp_ac_decoder;
+/**
+ * Contains information about an Acinerella video/audio decoder.
+ */
+typedef struct _ac_decoder {
+ /**
+ * Pointer on the Acinerella instance.
+ */
+ lp_ac_instance pacInstance;
-/*Contains information about an Acinerella package.*/
-struct _ac_package {
- /*The stream the package belongs to.*/
- int stream_index;
-};
+ /**
+ * Contains the type of the decoder.
+ */
+ ac_decoder_type type;
-typedef struct _ac_package ac_package;
-/*Pointer on TAc_package*/
-typedef ac_package* lp_ac_package;
+ /**
+ * The timecode of the currently decoded picture in seconds.
+ */
+ double timecode;
-/*Initializes an Acinerella instance.*/
-extern lp_ac_instance CALL_CONVT ac_init(void);
-extern void CALL_CONVT ac_free(lp_ac_instance pacInstance);
+ /**
+ * Contains information about the stream the decoder is attached to.
+ */
+ ac_stream_info stream_info;
-/*Opens a media file.*/
-
-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);
-
-/*Stores information in "pInfo" about stream number "nb".*/
-extern void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, lp_ac_stream_info info);
+ /**
+ * The index of the stream the decoder is attached to.
+ */
+ int stream_index;
-/*Reads a package from an opened media file.*/
-extern lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance);
-/*Frees a package that has been read.*/
-extern void CALL_CONVT ac_free_package(lp_ac_package pPackage);
+ /**
+ * Pointer to the buffer which contains the data.
+ */
+ uint8_t *pBuffer;
-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
- "buffer" property of the decoder.*/
-extern int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
-extern int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
+ /**
+ * Size of the data in the buffer.
+ */
+ int buffer_size;
+} ac_decoder;
+
+typedef ac_decoder *lp_ac_decoder;
+
+/**
+ * Contains information about an Acinerella package.
+ */
+typedef struct _ac_package {
+ /*The stream the package belongs to.*/
+ int stream_index;
+} ac_package;
+
+typedef ac_package *lp_ac_package;
+
+typedef void *lp_ac_proberesult;
+
+/**
+ * Callback function used to ask the application to read data. Should return
+ * the number of bytes read or an value smaller than zero if an error occured.
+ */
+typedef int (CALL_CONVT *ac_read_callback)(void *sender, uint8_t *buf,
+ int size);
+
+/**
+ * Callback function used to ask the application to seek.
+ *
+ * @param sender is the pointer specified in ac_open.
+ * @param pos is the position to which the stream should be seeked.
+ * @param whence specifies whether the seeking should be relative to the
+ * beginning of the file (0, SEEK_SET), relative to the current location (1,
+ * SEEK_CUR), or relative to the end of the file (2, SEEK_END)
+ * @return 0 if the function succeeds, -1 on failure.
+ */
+typedef int64_t (CALL_CONVT *ac_seek_callback)(void *sender, int64_t pos,
+ int whence);
+
+/**
+ * Callback function that is used to notify the application when the data stream
+ * is opened or closed. For example the file pointer should be resetted to zero
+ * when the "open" function is called.
+ */
+typedef int (CALL_CONVT *ac_openclose_callback)(void *sender);
+
+/**
+ * Initializes an Acinerella instance.
+ *
+ * @return a pointer at an acinerella instance. The instance must be freed using
+ * ac_free.
+ */
+EXTERN lp_ac_instance CALL_CONVT ac_init(void);
+
+/**
+* Initializes an Acinerella instance with a specific output format.
+*
+* @return a pointer at an acinerella instance. The instance must be freed using
+* ac_free.
+*/
+EXTERN lp_ac_instance CALL_CONVT ac_init_of(ac_output_format outputFormat);
+
+/**
+ * Frees a previously created Acinerella instance.
+ *
+ * @param pacInstance is the Acinerella instance that should be freed.
+ */
+EXTERN void CALL_CONVT ac_free(lp_ac_instance pacInstance);
+
+/**
+ * Opens a media stream.
+ *
+ * @param inst specifies the Acinerella Instance the stream should be opened
+ * for.
+ * @param sender specifies a pointer that is sent to all callback functions to
+ * allow you to do object orientated programming. May be NULL.
+ * @param open_proc specifies the callback function that is called, when the
+ * media file is opened. May be NULL.
+ * @param seek_proc specifies the callback function that is called, when the
+ * ffmpeg decoder wants to seek in the file. May be NULL.
+ * @param close_proc specifies the callback function that is called when the
+ * media file is closed. May be NULL.
+ * @param proberesult is a pointer at a structure previously returned by
+ * ac_probe_input_buffer. May be NULL.
+ */
+EXTERN int CALL_CONVT
+ ac_open(lp_ac_instance pacInstance, void *sender,
+ ac_openclose_callback open_proc, ac_read_callback read_proc,
+ ac_seek_callback seek_proc, ac_openclose_callback close_proc,
+ lp_ac_proberesult proberesult);
+
+/**
+ * Opens a media file.
+ *
+ * @param inst specifies the Acinerella Instance the stream should be opened
+ * for.
+ * @param file is the name of the file that should be opened.
+ */
+EXTERN int CALL_CONVT
+ ac_open_file(lp_ac_instance pacInstance, const char *filename);
+
+/**
+ * Closes an opened media file.
+ */
+EXTERN void CALL_CONVT ac_close(lp_ac_instance pacInstance);
+
+/**
+ * Stores information in "pInfo" about stream number "nb".
+ */
+EXTERN void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb,
+ lp_ac_stream_info info);
+
+/**
+ * Reads a package from an opened media file.
+ *
+ * @param pacInstance is the Acinerella instance from which the data should be
+ * read.
+ * @return a pointer at a ac_package structure or NULL on failure. The returned
+ * pointer must be freed with ac_free_package after use.
+ */
+EXTERN lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance);
+
+/**
+ * Frees a package that has been read.
+ *
+ * @param pPackage is a pointer at the ac_package that should be freed. May be
+ * NULL in which case no operation is performed.
+ */
+EXTERN void CALL_CONVT ac_free_package(lp_ac_package pPackage);
+
+/**
+ * Creates an decoder for the specified stream number. Returns NULL if no
+ * decoder could be found.
+ */
+EXTERN lp_ac_decoder CALL_CONVT
+ ac_create_decoder(lp_ac_instance pacInstance, int nb);
+
+/**
+ * Frees an created decoder.
+ */
+EXTERN void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder);
+
+/**
+ * Decodes a package using the specified decoder. The decoded data is stored in
+ * the "buffer" property of the decoder.
+ *
+ * @param pPackage is the package that should be decoded, previously read by the
+ * ac_read_package method.
+ * @param pDecoder is the decoder instance that should be used to decode the
+ * package -- use the stream index stored in the package to determine the
+ * correct decoder.
+ */
+EXTERN int CALL_CONVT
+ ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
+
+/**
+* Decodes a package using the specified decoder and skips it. Returns true if a frame was skiped.
+*
+* @param pPackage is the package that should be decoded, previously read by the
+* ac_read_package method.
+* @param pDecoder is the decoder instance that should be used to decode the
+* package -- use the stream index stored in the package to determine the
+* correct decoder.
+*/
+EXTERN int CALL_CONVT
+ ac_skip_package(lp_ac_package pPackage, lp_ac_decoder pDecoder);
+
+/**
+* Decodes a packages using the specified decoder and skips num frames. Returns true if num frames where skiped.
+*
+* @param pacInstance is the Acinerella instance from which the data should be
+* read.
+* @param pDecoder is the decoder instance that should be used to decode the
+* package -- use the stream index stored in the package to determine the
+* correct decoder.
+* @num number of frames to skip.
+*/
+EXTERN int CALL_CONVT
+ ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num);
+
+/**
+* Decodes a video frame using the specified decoder and strores the result in the decoder. Returns true if a frame cloud be decoded.
+*
+* @param pacInstance is the Acinerella instance from which the data should be
+* read.
+* @param pDecoder is the decoder instance that should be used to decode the
+* package -- use the stream index stored in the package to determine the
+* correct decoder.
+*/
+EXTERN int CALL_CONVT
+ ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder);
+
+/**
+* Decodes a audio frame using the specified decoder and strores the result in the decoder. Returns true if a frame cloud be decoded.
+*
+* @param pacInstance is the Acinerella instance from which the data should be
+* read.
+* @param pDecoder is the decoder instance that should be used to decode the
+* package -- use the stream index stored in the package to determine the
+* correct decoder.
+*/
+EXTERN int CALL_CONVT
+ ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder);
+
+
+/**
+ * Seeks to the given target position in the file. The seek funtion is not able
+ * to seek a single audio/video stream but seeks the whole file forward. The
+ * stream number paremter (nb) is only used for the timecode reference.
+ * The parameter "dir" specifies the seek direction: 0 for forward, -1 for
+ * backward. The target_pos paremeter is in milliseconds. Returns 1 if the
+ * functions succeded.
+ */
+EXTERN int CALL_CONVT
+ ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos);
+
+/**
+ * Checks whether the given input buffer contains data that can potentially be
+ * decoded by Acinerella. If yes, returns a pointer that may be passed to
+ * ac_open in order to speed up the open process. Otherwise returns NULL.
+ *
+ * @param buf is a pointer to the buffer in which the data is stored.
+ * @param bufsize is the size of the buffer.
+ * @param filename is the name of the file the buffer originated from. May be
+ * empty or NULL.
+ * @param score_max is set to the maximum of the previous value of score_max
+ * and an internal score value.
+ * @return either a pointer at an internal "probe result" or NULL if the buffer
+ * contains no decodeable data.
+ */
+EXTERN lp_ac_proberesult CALL_CONVT
+ ac_probe_input_buffer(uint8_t *buf, int bufsize, char *filename,
+ int *score_max);
+
+#endif /* _ACINERELLA_H_ */
-extern int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder);
-extern int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder);
-extern int CALL_CONVT ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num);
-
-/*Seeks to the given target position in the file. The seek funtion is not able to seek a single audio/video stream
-but seeks the whole file forward. The stream number paremter (nb) is only used for the timecode reference.
-The parameter "dir" specifies the seek direction: 0 for forward, -1 for backward.
-The target_pos paremeter is in milliseconds. Returns 1 if the functions succeded.*/
-extern int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos);
-#endif /*VIDEOPLAY_H*/
diff --git a/Vocaluxe/Screens/CScreenMain.cs b/Vocaluxe/Screens/CScreenMain.cs
index a884c016..e1f2a424 100644
--- a/Vocaluxe/Screens/CScreenMain.cs
+++ b/Vocaluxe/Screens/CScreenMain.cs
@@ -57,6 +57,7 @@ namespace Vocaluxe.Screens
_Texts[_TextRelease].Visible = true;
_Statics[_StaticWarningProfiles].Visible = false;
_Texts[_TextWarningProfiles].Visible = false;
+ _SelectElement(_Buttons[_ButtonSing]);
}
public override bool HandleInput(SKeyEvent keyEvent)
@@ -105,6 +106,10 @@ namespace Vocaluxe.Screens
return false;
break;
+
+ case Keys.Escape:
+ _SelectElement(_Buttons[_ButtonExit]);
+ break;
}
}
return true;
diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj
index 010461d9..248e7a46 100644
--- a/Vocaluxe/Vocaluxe.csproj
+++ b/Vocaluxe/Vocaluxe.csproj
@@ -535,10 +535,10 @@
This project references NuGet package(s) that are missing on this computer. Rebuild for automatic package restore. The missing file is {0}.
-
+
-
+
@@ -547,12 +547,12 @@
-
+
-
+
-
+
@@ -561,5 +561,5 @@
-
+
\ No newline at end of file
diff --git a/Vocaluxe/packages.config b/Vocaluxe/packages.config
index b9d40591..437d7321 100644
--- a/Vocaluxe/packages.config
+++ b/Vocaluxe/packages.config
@@ -1,10 +1,10 @@
-
-
+
+
-
+
diff --git a/appveyor.yml b/appveyor.yml
index e614e1a2..004abdfd 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -80,6 +80,8 @@ after_build:
test: off
before_deploy:
- ps: ./.appveyor/prepareDeploy.ps1
+after_deploy:
+- ps: ./.appveyor/afterDeploy.ps1
deploy:
- provider: GitHub
tag: $(APPVEYOR_REPO_TAG_NAME)
@@ -88,7 +90,7 @@ deploy:
auth_token:
secure: JSlN/em0JdspVn8jwaQ4IjugY6OQi0au4Qq0rhctJmcfGMaEGnUAOmDFULI48REW
artifact: ReleaseZip
- prerelease: true
+ prerelease: $(IS_BETA_RELEASE)
on:
APPVEYOR_REPO_TAG: true
NIGHTLY_BUILD: false
@@ -96,10 +98,11 @@ deploy:
- provider: GitHub
tag: $(APPVEYOR_REPO_TAG_NAME)
release: Latest Nightly build
- description:
+ description: $(APPVEYOR_REPO_COMMIT)
auth_token:
secure: JSlN/em0JdspVn8jwaQ4IjugY6OQi0au4Qq0rhctJmcfGMaEGnUAOmDFULI48REW
artifact: ReleaseZip
+ prerelease: true
on:
APPVEYOR_REPO_TAG: true
NIGHTLY_BUILD: true