📄 libovd.cpp
字号:
#include <windows.h>
#include <tchar.h>
#include "libovd.h"
#include ".\tremor\ivorbiscodec.h"
#include ".\tremor\ivorbisfile.h"
#include ".\tremor\codebook.h"
#include ".\tremor\misc.h"
typedef struct
{
FILE* fp;
OggVorbis_File vf;
}LIBOV_STRUCT;
extern "C" void *calloc2( size_t num, size_t size )
{
void* p = malloc(num * size);
if (!p) return p;
memset(p, 0, num * size);
return p;
}
int UTF8toUCS2(char* pszSrc, WCHAR* pszDst, DWORD dwDstLen)
{
DWORD dwLen = 0;
while (*pszSrc) {
if (++dwLen == dwDstLen)
break;
if ((*pszSrc & 0x80) == 0x0) {
// 1 byte
*pszDst++ = *pszSrc++;
}
else if ((*pszSrc & 0xE0) == 0xC0) {
// 2 bytes
*pszDst++ = (((WORD)*pszSrc & 0x1F) << 6) | ((WORD)*(pszSrc + 1) & 0x3F);
pszSrc += 2;
}
else if ((*pszSrc & 0xE0) == 0xE0) {
// 3 bytes
*pszDst++ = (((WORD)*pszSrc & 0x0F) << 12) | (((WORD)*(pszSrc + 1) & 0x3F) << 6) | ((WORD)*(pszSrc + 2) & 0x3F);
pszSrc += 3;
}
}
*pszDst = NULL;
return dwLen;
}
BOOL ovd_test_file(LPCTSTR pszFile)
{
if (!_tcslen(pszFile))
return FALSE;
FILE* fp = _tfopen(pszFile, _T("rb"));
if (!fp)
return NULL;
OggVorbis_File vf;
int ret = ov_test(fp, &vf, NULL, 0);
fclose(fp);
ov_clear(&vf);
return ret == 0;
}
HANDLE ovd_open_file(LPCTSTR pszFile)
{
if (!_tcslen(pszFile))
return NULL;
FILE* fp = _tfopen(pszFile, _T("rb"));
if (!fp)
return NULL;
LIBOV_STRUCT* lov = new LIBOV_STRUCT;
if (ov_open(fp, &lov->vf, NULL, 0) < 0)
{
delete lov;
fclose(fp);
return NULL;
}
lov->fp = fp;
return (HANDLE)lov;
}
void ovd_close(HANDLE hov)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return;
ov_clear(&lov->vf);
if (lov->fp)
fclose(lov->fp);
delete lov;
}
int ovd_read(HANDLE hov, LPBYTE pcmbuf, int pcmbuf_len, int* pcmout)
{
*pcmout = 0;
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return OVD_FATAL_ERR;
if (pcmbuf_len < OVD_PCMBUF_LEN)
return OVD_NEED_MORE_OUTPUT;
int ret = ov_read(&lov->vf, (char*)pcmbuf, pcmbuf_len, NULL);
if (ret == 0) // eof
return OVD_EOF;
else if (ret < 0) // error
return OVD_FATAL_ERR;
// succeeded
*pcmout = ret;
return OVD_OK;
}
BOOL ovd_seek(HANDLE hov, LONGLONG samples)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return FALSE;
return ov_pcm_seek_page(&lov->vf, samples) == 0;
}
LONGLONG ovd_get_current(HANDLE hov)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return FALSE;
return ov_pcm_tell(&lov->vf);
}
LONGLONG ovd_get_duration(HANDLE hov)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return FALSE;
return ov_pcm_total(&lov->vf, -1);
}
BOOL ovd_get_info(HANDLE hov, ovd_info* info)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return FALSE;
vorbis_info* pvi = ov_info(&lov->vf, -1);
if (!pvi)
return FALSE;
info->version = pvi->version;
info->rate = pvi->rate;
info->channels = pvi->channels;
info->bitrate_lower = pvi->bitrate_lower;
info->bitrate_nominal = pvi->bitrate_nominal;
info->bitrate_upper = pvi->bitrate_upper;
info->bitrate_window = pvi->bitrate_window;
return TRUE;
}
void ovd_strupr(char* str)
{
for (int i = 0; str[i] != NULL; i++) {
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 'a' - 'A';
}
}
#define OVD_COMMENT_TITLE "TITLE"
#define OVD_COMMENT_ARTIST "ARTIST"
#define OVD_COMMENT_ALBUM "ALBUM"
#define OVD_COMMENT_GENRE "GENRE"
#define OVD_COMMENT_COMMENT "COMMENT"
#define OVD_COMMENT_DATE "DATE"
#define OVD_COMMENT_TRACKNUM "TRACKNUMBER"
BOOL ovd_get_comment(HANDLE hov, ovd_comment* comment)
{
LIBOV_STRUCT* lov = (LIBOV_STRUCT*)hov;
if (!lov) return FALSE;
memset(comment, 0, sizeof(ovd_comment));
vorbis_comment* p = ov_comment(&lov->vf, -1);
for (int i = 0; i < p->comments; i++)
{
LPTSTR psz = NULL;
char* s = strchr(p->user_comments[i], '=');
if (s)
{
*s = NULL;
ovd_strupr(p->user_comments[i]);
if (strcmp(p->user_comments[i], OVD_COMMENT_DATE) == 0)
psz = comment->szDate;
else if (strcmp(p->user_comments[i], OVD_COMMENT_TRACKNUM) == 0)
psz = comment->szTrackNum;
else if (strcmp(p->user_comments[i], OVD_COMMENT_TITLE) == 0)
psz = comment->szTitle;
else if (strcmp(p->user_comments[i], OVD_COMMENT_ARTIST) == 0)
psz = comment->szArtist;
else if (strcmp(p->user_comments[i], OVD_COMMENT_ALBUM) == 0)
psz = comment->szAlbum;
else if (strcmp(p->user_comments[i], OVD_COMMENT_GENRE) == 0)
psz = comment->szGenre;
else if (strcmp(p->user_comments[i], OVD_COMMENT_COMMENT) == 0)
psz = comment->szComment;
if (psz)
{
#ifdef _UNICODE
UTF8toUCS2(s + 1, psz, OVD_COMMENT_LEN);
#else
WCHAR sz[OVD_COMMENT_LEN];
UTF8toUCS2(s + 1, sz, OVD_COMMENT_LEN);
WideCharToMultiByte(CP_ACP, 0, sz, -1, psz, OVD_COMMENT_LEN, 0, 0);
#endif
}
}
}
return TRUE;
}
BOOL ovd_get_comment_from_file(LPCTSTR pszFile, ovd_comment* comment)
{
if (!ovd_test_file(pszFile))
return FALSE;
FILE* fp = _tfopen(pszFile, _T("rb"));
if (!fp)
return FALSE;
OggVorbis_File vf;
if (ov_open(fp, &vf, NULL, 0) < 0)
{
fclose(fp);
return FALSE;
}
memset(comment, 0, sizeof(ovd_comment));
vorbis_comment* p = ov_comment(&vf, -1);
for (int i = 0; i < p->comments; i++)
{
LPTSTR psz = NULL;
char* s = strchr(p->user_comments[i], '=');
if (s)
{
*s = NULL;
ovd_strupr(p->user_comments[i]);
if (strcmp(p->user_comments[i], OVD_COMMENT_DATE) == 0)
psz = comment->szDate;
else if (strcmp(p->user_comments[i], OVD_COMMENT_TRACKNUM) == 0)
psz = comment->szTrackNum;
else if (strcmp(p->user_comments[i], OVD_COMMENT_TITLE) == 0)
psz = comment->szTitle;
else if (strcmp(p->user_comments[i], OVD_COMMENT_ARTIST) == 0)
psz = comment->szArtist;
else if (strcmp(p->user_comments[i], OVD_COMMENT_ALBUM) == 0)
psz = comment->szAlbum;
else if (strcmp(p->user_comments[i], OVD_COMMENT_GENRE) == 0)
psz = comment->szGenre;
else if (strcmp(p->user_comments[i], OVD_COMMENT_COMMENT) == 0)
psz = comment->szComment;
if (psz)
{
#ifdef _UNICODE
UTF8toUCS2(s + 1, psz, OVD_COMMENT_LEN);
#else
WCHAR sz[OVD_COMMENT_LEN];
UTF8toUCS2(s + 1, sz, OVD_COMMENT_LEN);
WideCharToMultiByte(CP_ACP, 0, sz, -1, psz, OVD_COMMENT_LEN, 0, 0);
#endif
}
}
}
fclose(fp);
return TRUE;
}
// for streaming
typedef struct {
int init;
ogg_sync_state oy;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
vorbis_info vi;
vorbis_comment vc;
vorbis_dsp_state vd;
vorbis_block vb;
int samples;
int eof;
ogg_int32_t **pcm;
} ovd_handle;
ovd_stream_buf* ovd_init_stream()
{
ovd_handle* handle = new ovd_handle;
memset(handle, 0, sizeof(ovd_handle));
ogg_sync_init(&handle->oy);
ovd_stream_buf* ret = new ovd_stream_buf;
ret->handle = (HANDLE)handle;
ret->buf = ogg_sync_buffer(&handle->oy, OVD_STREAM_BUF_LEN);
ret->len = OVD_STREAM_BUF_LEN;
return ret;
}
int ovd_header_init(ovd_handle* handle)
{
if (handle->init < 2) {
if (handle->init < 0)
return -1;
while (handle->init < 2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -