Commit 14571fd2 authored by 藤森雅人's avatar 藤森雅人
Browse files

Initial commit

parents
#include <opus_types.h>
#include <opus.h>
#include <cstring>
#include <memory>
#include <vector>
// https://github.com/mackron/dr_libs/blob/master/dr_wav.h
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
#define FRAME_SIZE 480
#define MAX_FRAME_SIZE (6*FRAME_SIZE)
#define MAX_CHANNELS 1
#define MAX_PACKET_SIZE (3*1276)
#pragma pack(push)
#pragma pack(1)
struct WavInfo {
uint16_t channels;
uint32_t sampleRate;
uint32_t bitsPerSample;
};
#pragma pack(pop)
#ifndef nullptr
#define nullptr NULL
#endif
class FileStream {
public:
FileStream() {
cur_pos = 0;
}
void Append(const char *data, size_t size) {
if (cur_pos + size > Size()) {
vec.resize(cur_pos + size);
}
memcpy(vec.data() + cur_pos, data, size);
cur_pos += size;
}
void AppendU32(uint32_t val) {
Append((char *)(&val), sizeof(val));
}
char *Data() {
return vec.data();
}
size_t Size() {
return vec.size();
}
size_t Read(void *buff, size_t elemSize, size_t elemCount) {
size_t readed = min((vec.size() - cur_pos), (elemCount * elemSize)) / elemSize;
if (readed > 0) {
memcpy(buff, vec.data() + cur_pos, readed * elemSize);
cur_pos += readed * elemSize;
}
return readed;
}
bool SeekCur(int offset) {
if (cur_pos + offset > vec.size()) {
cur_pos = !vec.empty() ? (vec.size() - 1) : 0;
return false;
}
else {
cur_pos += offset;
return true;
}
}
bool SeekBeg(int offset = 0) {
cur_pos = 0;
return SeekCur(offset);
}
bool WriteToFile(const char *filename) {
FILE *fin;
fopen_s(&fin, filename, "wb");
if (!fin) {
return false;
}
fseek(fin, 0, SEEK_SET);
fwrite(vec.data(), sizeof(char), vec.size(), fin);
fclose(fin);
return true;
}
bool ReadFromFile(const char *filename) {
FILE *fin;
fopen_s(&fin, filename, "rb");
if (!fin) {
return false;
}
fseek(fin, 0, SEEK_END);
long fileSize = ftell(fin);
vec.resize(static_cast<unsigned long long int>(fileSize));
fseek(fin, 0, SEEK_SET);
fread(vec.data(), sizeof(char), vec.size(), fin);
fclose(fin);
return true;
}
private:
std::vector<char> vec;
size_t cur_pos;
};
bool Wav2Opus(FileStream *input, FileStream *output);
bool Opus2Wav(FileStream *input, FileStream *output);
bool wav2stream(char *input, FileStream *output);
bool stream2wav(FileStream *input, char *output);
bool wavWrite_int16(char *filename, int16_t *buffer, int sampleRate, uint32_t totalSampleCount) {
drwav_data_format format = {};
format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
format.channels = 1;
format.sampleRate = (drwav_uint32)sampleRate;
format.bitsPerSample = 16;
drwav *pWav = drwav_open_file_write(filename, &format);
if (pWav) {
drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer);
drwav_uninit(pWav);
if (samplesWritten != totalSampleCount) {
fprintf(stderr, "ERROR\n");
return false;
}
return true;
}
return false;
}
int16_t *wavRead_int16(char *filename, uint32_t *sampleRate, uint64_t *totalSampleCount) {
unsigned int channels;
int16_t *buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
if (buffer == nullptr) {
ods("[wavRead_int16() buffer==nullptr]\n");
fprintf(stderr, "ERROR\n");
return nullptr;
}
if (channels != 1) {
ods("[wavRead_int16() channels!=1]\n");
drwav_free(buffer);
buffer = nullptr;
*sampleRate = 0;
*totalSampleCount = 0;
}
return buffer;
}
bool wav2stream(char *input, FileStream *output) {
uint32_t sampleRate = 0;
uint64_t totalSampleCount = 0;
int16_t *wavBuffer = wavRead_int16(input, &sampleRate, &totalSampleCount);
if (wavBuffer == nullptr)
{
return false;
}
WavInfo info = {};
info.bitsPerSample = 16;
info.sampleRate = sampleRate;
info.channels = 1;
output->SeekBeg();
output->Append((char *)&info, sizeof(info));
output->Append((char *)wavBuffer, (size_t)(totalSampleCount * sizeof(int16_t)));
free(wavBuffer);
return true;
}
bool stream2wav(FileStream *input, char *output) {
WavInfo info = {};
input->SeekBeg();
size_t read = input->Read(&info, sizeof(info), 1);
if (read != 1) {
return false;
}
size_t totalSampleCount = (input->Size() - sizeof(info)) / 2;
return wavWrite_int16(output, (int16_t *)(input->Data() + sizeof(info)), info.sampleRate,
static_cast<uint32_t>(totalSampleCount));
}
bool Wav2Opus(FileStream *input, FileStream *output) {
WavInfo in_info = {};
input->SeekBeg();
size_t read = input->Read(&in_info, sizeof(in_info), 1);
if (read != 1) {
return false;
}
uint32_t bitsPerSample = in_info.bitsPerSample;
uint32_t sampleRate = in_info.sampleRate;
uint16_t channels = in_info.channels;
int err = 0;
if (channels > MAX_CHANNELS) {
return false;
}
OpusEncoder *encoder = opus_encoder_create(sampleRate, channels, OPUS_APPLICATION_AUDIO, &err);
if (!encoder || err < 0) {
fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
if (!encoder) {
opus_encoder_destroy(encoder);
}
return false;
}
const uint16_t *data = (uint16_t *)(input->Data() + sizeof(in_info));
size_t size = (input->Size() - sizeof(in_info)) / 2;
opus_int16 pcm_bytes[FRAME_SIZE * MAX_CHANNELS];
size_t index = 0;
size_t step = static_cast<size_t>(FRAME_SIZE * channels);
FileStream encodedData;
unsigned char cbits[MAX_PACKET_SIZE];
size_t frameCount = 0;
size_t readCount = 0;
while (index < size) {
memset(&pcm_bytes, 0, sizeof(pcm_bytes));
if (index + step <= size) {
memcpy(pcm_bytes, data + index, step * sizeof(uint16_t));
index += step;
}
else {
readCount = size - index;
memcpy(pcm_bytes, data + index, (readCount) * sizeof(uint16_t));
index += readCount;
}
int nbBytes = opus_encode(encoder, pcm_bytes, channels * FRAME_SIZE, cbits, MAX_PACKET_SIZE);
if (nbBytes < 0) {
fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
break;
}
++frameCount;
encodedData.AppendU32(static_cast<uint32_t>(nbBytes));
encodedData.Append((char *)cbits, static_cast<size_t>(nbBytes));
}
WavInfo info = {};
info.bitsPerSample = bitsPerSample;
info.sampleRate = sampleRate;
info.channels = channels;
output->SeekBeg();
output->Append((char *)&info, sizeof(info));
output->Append(encodedData.Data(), encodedData.Size());
opus_encoder_destroy(encoder);
return true;
}
bool Opus2Wav(FileStream *input, FileStream *output) {
WavInfo info = {};
input->SeekBeg();
size_t read = input->Read(&info, sizeof(info), 1);
if (read != 1) {
return false;
}
int channels = info.channels;
if (channels > MAX_CHANNELS) {
return false;
}
output->SeekBeg();
output->Append((char *)&info, sizeof(info));
int err = 0;
OpusDecoder *decoder = opus_decoder_create(info.sampleRate, channels, &err);
if (!decoder || err < 0) {
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
if (!decoder) {
opus_decoder_destroy(decoder);
}
return false;
}
unsigned char cbits[MAX_PACKET_SIZE];
opus_int16 out[MAX_FRAME_SIZE * MAX_CHANNELS];
int frameCount = 0;
while (true) {
uint32_t nbBytes;
size_t readed = input->Read(&nbBytes, sizeof(uint32_t), 1);
if (readed == 0) {
break;
}
if (nbBytes > sizeof(cbits)) {
fprintf(stderr, "nbBytes > sizeof(cbits)\n");
break;
}
readed = input->Read(cbits, sizeof(char), nbBytes);
if (readed != nbBytes) {
fprintf(stderr, "readed != nbBytes\n");
break;
}
int frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0);
if (frame_size < 0) {
fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
break;
}
++frameCount;
output->Append((char *)out, channels * frame_size * sizeof(out[0]));
}
opus_decoder_destroy(decoder);
return true;
}
void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
const char *end;
const char *p;
const char *s;
if (path[0] && path[1] == ':') {
if (drv) {
*drv++ = *path++;
*drv++ = *path++;
*drv = '\0';
}
}
else if (drv)
*drv = '\0';
for (end = path; *end && *end != ':';)
end++;
for (p = end; p > path && *--p != '\\' && *p != '/';)
if (*p == '.') {
end = p;
break;
}
if (ext)
for (s = end; (*ext = *s++);)
ext++;
for (p = end; p > path;)
if (*--p == '\\' || *p == '/') {
p++;
break;
}
if (name) {
for (s = p; s < end;)
*name++ = *s++;
*name = '\0';
}
if (dir) {
for (s = path; s < p;)
*dir++ = *s++;
*dir = '\0';
}
}
void opus2wav(const char *in_file, char *out_file) {
FileStream input;
FileStream output;
input.ReadFromFile(in_file);
Opus2Wav(&input, &output);
stream2wav(&output, out_file);
}
void wav2opus(char *in_file, char *out_file) {
FileStream input;
FileStream output;
if (wav2stream(in_file, &input))
{
ods("[wav2stream] OK\n");
}
else
{
ods("[wav2stream] NG\n");
}
if (Wav2Opus(&input, &output))
{
ods("[Wav2Opus] OK\n");
}
else
{
ods("[Wav2Opus] NG\n");
}
output.WriteToFile(out_file);
}
#if 0
int convert(char *path) {
char *in_file = path;
char drive[3];
char dir[256];
char fname[256];
char ext[256];
char out_file[1024];
splitpath(in_file, drive, dir, fname, ext);
if (memcmp(".wav", ext, strlen(ext)) == 0) {
sprintf_s(out_file, "%s%s%s.opus", drive, dir, fname);
wav2opus(in_file, out_file);
}
else if (memcmp(".opus", ext, strlen(ext)) == 0) {
sprintf_s(out_file, "%s%s%s_opus.wav", drive, dir, fname);
opus2wav(in_file, out_file);
}
return 0;
}
#endif
\ No newline at end of file
#include "stdafx.h"
#if defined(_WIN32)
# include <stdio.h>
# include <stdlib.h>
# include <wchar.h>
/*We need the following two to set stdin/stdout to binary.*/
# include <io.h>
# include <fcntl.h>
# define WIN32_LEAN_AND_MEAN
# define WIN32_EXTRA_LEAN
# include <windows.h>
# include "win32utf8.h"
static char *utf16_to_utf8(const wchar_t *_src) {
char *dst;
size_t len;
size_t si;
size_t di;
len = wcslen(_src);
dst = (char *)malloc(sizeof(*dst)*(3 * len + 1));
if (dst == NULL)return dst;
for (di = si = 0; si < len; si++) {
unsigned c0;
c0 = _src[si];
if (c0 < 0x80) {
/*Can be represented by a 1-byte sequence.*/
dst[di++] = (char)c0;
continue;
}
else if (c0 < 0x800) {
/*Can be represented by a 2-byte sequence.*/
dst[di++] = (char)(0xC0 | c0 >> 6);
dst[di++] = (char)(0x80 | c0 & 0x3F);
continue;
}
else if (c0 >= 0xD800 && c0 < 0xDC00) {
unsigned c1;
/*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
c1 = _src[si + 1];
if (c1 >= 0xDC00 && c1 < 0xE000) {
unsigned w;
/*Surrogate pair.*/
w = ((c0 & 0x3FF) << 10 | c1 & 0x3FF) + 0x10000;
/*Can be represented by a 4-byte sequence.*/
dst[di++] = (char)(0xF0 | w >> 18);
dst[di++] = (char)(0x80 | w >> 12 & 0x3F);
dst[di++] = (char)(0x80 | w >> 6 & 0x3F);
dst[di++] = (char)(0x80 | w & 0x3F);
si++;
continue;
}
}
/*Anything else is either a valid 3-byte sequence, an invalid surrogate
pair, or 'not a character'.
In the latter two cases, we just encode the value as a 3-byte
sequence anyway (producing technically invalid UTF-8).
Later error handling will detect the problem, with a better
chance of giving a useful error message.*/
dst[di++] = (char)(0xE0 | c0 >> 12);
dst[di++] = (char)(0x80 | c0 >> 6 & 0x3F);
dst[di++] = (char)(0x80 | c0 & 0x3F);
}
dst[di++] = '\0';
return dst;
}
typedef LPWSTR *(APIENTRY *command_line_to_argv_w_func)(LPCWSTR cmd_line,
int *num_args);
/*Make a best-effort attempt to support UTF-8 on Windows.*/
void win32_utf8_setup(int *_argc, const char ***_argv) {
HMODULE hlib;
/*We need to set stdin/stdout to binary mode.
This is unrelated to UTF-8 support, but it's platform specific and we need
to do it in the same places.*/
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
hlib = LoadLibraryA("shell32.dll");
if (hlib != NULL) {
command_line_to_argv_w_func command_line_to_argv_w;
/*This function is only available on Windows 2000 or later.*/
command_line_to_argv_w = (command_line_to_argv_w_func)GetProcAddress(hlib,
"CommandLineToArgvW");
if (command_line_to_argv_w != NULL) {
wchar_t **argvw;
int argc;
argvw = (*command_line_to_argv_w)(GetCommandLineW(), &argc);
if (argvw != NULL) {
int ai;
/*Really, I don't see why argc would ever differ from *_argc, but let's
be paranoid.*/
if (argc > *_argc)argc = *_argc;
for (ai = 0; ai < argc; ai++) {
char *argv;
argv = utf16_to_utf8(argvw[ai]);
if (argv != NULL)(*_argv)[ai] = argv;
}
*_argc = argc;
LocalFree(argvw);
}
}
FreeLibrary(hlib);
}
# if defined(CP_UTF8)
/*This does not work correctly in all environments (it breaks output in
mingw32 for me), and requires a Unicode font (e.g., when using the default
Raster font, even characters that are available in the font's codepage
won't display properly).*/
/*SetConsoleOutputCP(CP_UTF8);*/
# endif
}
#endif
\ No newline at end of file
#pragma once
#if !defined(_win32utf8_H)
# define _win32utf8_H (1)
# if defined(_WIN32)
/*Make a best-effort attempt to support UTF-8 on Windows.*/
void win32_utf8_setup(int *_argc, const char ***_argv);
# endif
#endif
\ No newline at end of file
[cpprestsdk_static_tester]ファイル構成
2019年7月26日 藤森雅人
MFCApplication2.sln
 Visual Studio 2017(Visual C++)のソリューションファイル。
[MFCApplication2]
 プログラム本体が入っているプロジェクトフォルダ。
[Debug]
 プログラムの実行ファイルが入っている。
 消してもビルドすれば作られる。
[libopusenc] [vcpkg] [libopusfile] [libopus] [libogg]
 プログラムに必要なライブラリ。
 ヘッダファイルと静的リンクライブラリがそれぞれ
 [include] [lib] に入っている。
Monty <monty@xiph.org>
Greg Maxwell <greg@xiph.org>
Ralph Giles <giles@xiph.org>
Cristian Adam <cristian.adam@gmail.com>
Tim Terriberry <tterribe@xiph.org>
and the rest of the Xiph.Org Foundation.
Version 1.3.3 (2017 November 7)
* Fix and issue with corrupt continued packet handling.
* Update Windows projects and build settings.
* Remove Mac OS 9 build support.
Version 1.3.2 (2014 May 27)
* Fix an bug in oggpack_writecopy().
Version 1.3.1 (2013 May 12)
* Guard against very large packets.
* Respect the configure --docdir override.
* Documentation fixes.
* More Windows build fixes.
Version 1.3.0 (2011 August 4)
* Add ogg_stream_flush_fill() call
This produces longer packets on flush, similar to
what ogg_stream_pageout_fill() does for single pages.
* Windows build fixes
Version 1.2.2 (2010 December 07)
* Build fix (types correction) for Mac OS X
* Update win32 project files to Visual Studio 2008
* ogg_stream_pageout_fill documentation fix
Version 1.2.1 (2010 November 01)
* Various build updates (see SVN)
* Add ogg_stream_pageout_fill() to API to allow applications
greater explicit flexibility in page sizing.
* Documentation updates including multiplexing description,
terminology and API (incl. ogg_packet_clear(),
ogg_stream_pageout_fill())
* Correct possible buffer overwrite in stream encoding on 32 bit
when a single packet exceed 250MB.
* Correct read-buffer overrun [without side effects] under
similar circumstances.
* Update unit testing to work properly with new page spill
heuristic.
Version 1.2.0 (2010 March 25)
* Alter default flushing behavior to span less often and use larger page
sizes when packet sizes are large.
* Build fixes for additional compilers
* Documentation updates
Version 1.1.4 (2009 June 24)
* New async error reporting mechanism. Calls made after a fatal error are
now safely handled in the event an error code is ignored
* Added allocation checks useful to some embedded applications
* fix possible read past end of buffer when reading 0 bits
* Updates to API documentation
* Build fixes
Version 1.1.3 (2005 November 27)
* Correct a bug in the granulepos field of pages where no packet ends
* New VS2003 and XCode builds, minor fixes to other builds
* documentation fixes and cleanup
Version 1.1.2 (2004 September 23)
* fix a bug with multipage packet assembly after seek
Version 1.1.1 (2004 September 12)
* various bugfixes
* important bugfix for 64-bit platforms
* various portability fixes
* autotools cleanup from Thomas Vander Stichele
* Symbian OS build support from Colin Ward at CSIRO
* new multiplexed Ogg stream documentation
Version 1.1 (2003 November 17)
* big-endian bitpacker routines for Theora
* various portability fixes
* improved API documenation
* RFC 3533 documentation of the format by Silvia Pfeiffer at CSIRO
* RFC 3534 documentation of the application/ogg mime-type by Linus Walleij
Version 1.0 (2002 July 19)
* First stable release
* little-endian bitpacker routines for Vorbis
* basic Ogg bitstream sync and coding support
Copyright (c) 2002, Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## Process this file with automake to produce Makefile.in
#AUTOMAKE_OPTIONS = foreign 1.6 dist-zip
AUTOMAKE_OPTIONS = foreign 1.11 dist-zip dist-xz
SUBDIRS = src include doc
m4datadir = $(datadir)/aclocal
m4data_DATA = ogg.m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = ogg.pc
EXTRA_DIST = README.md AUTHORS CHANGES COPYING \
libogg.spec libogg.spec.in \
ogg.m4 ogg.pc.in ogg-uninstalled.pc.in \
macosx win32
dist-hook:
for item in $(EXTRA_DIST); do \
if test -d $$item; then \
echo -n "cleaning dir $$item for distribution..."; \
rm -rf `find $(distdir)/$$item -name .svn`; \
echo "OK"; \
fi; \
done
debug:
$(MAKE) all CFLAGS="@DEBUG@"
profile:
$(MAKE) all CFLAGS="@PROFILE@"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment