PDA

Просмотр полной версии : Играем мр3, мр4(h264), wav(pcm), atrac, aac


l3VGV
01.07.2007, 18:22
Итак, рабочий пример без внешних либ, тока средцтвами самой консольки.


#include <pspkernel.h>
#include <pspctrl.h>
#include <pspmpeg.h>
#include <pspdisplay.h>
#include <pspdebug.h>
#include <psppower.h>
#include <stdio.h>
#include <stdlib.h>
#include <pspkernel.h>
#include <pspctrl.h>
#include <psppower.h>
#include <pspdebug.h>
#include <psprtc.h>
#include <pspsdk.h>
#include <pspaudiocodec.h>
#include <pspaudio.h>
#include <string.h>
#include <malloc.h>

int SetupCallbacks();

PSP_MODULE_INFO("MP3 decodeTest", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);

__attribute__ ((constructor))
void loaderInit(){
pspKernelSetKernelPC();
pspSdkInstallNoDeviceCheckPatch();
pspSdkInstallNoPlainModuleCheckPatch();
pspSdkInstallKernelLoadModulePatch();
}

SceCtrlData input;

static int bitrates[] = {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 };

unsigned long mp3_codec_buffer[65] __attribute__((aligned(64)));
short mp3_mix_buffer1[1152 * 2] __attribute__((aligned(64)));
short mp3_mix_buffer2[1152 * 2] __attribute__((aligned(64)));

SceUID mp3_handle;
u8* mp3_data_buffer;
u16 mp3_data_align;
u32 mp3_sample_per_frame;
u16 mp3_channel_mode;
u32 mp3_data_start;
u32 mp3_data_size;
u8 mp3_getEDRAM;
u32 mp3_channels;
u32 mp3_samplerate;
int donext, bc, eof;

SceCtrlData pad;


int decode_thread(SceSize args, void *argp)
{

eof = 0;
fprintf(stderr,"$>entering main loop\n");
while( !eof ) {
if (!donext)
{
sceKernelDelayThread(1);
continue;
}

int samplesdecoded;

if (!bc)
memset(mp3_mix_buffer1, 0, mp3_sample_per_frame*2*2);
else
memset(mp3_mix_buffer2, 0, mp3_sample_per_frame*2*2);

unsigned char mp3_header_buf[4];
if ( sceIoRead( mp3_handle, mp3_header_buf, 4 ) != 4 ) {
fprintf(stderr,"$>mp3_header_buf < 4 exitin \n");
eof = 1;
continue;
}
int mp3_header = mp3_header_buf[0];
mp3_header = (mp3_header<<8) | mp3_header_buf[1];
mp3_header = (mp3_header<<8) | mp3_header_buf[2];
mp3_header = (mp3_header<<8) | mp3_header_buf[3];

int bitrate = (mp3_header & 0xf000) >> 12;
int padding = (mp3_header & 0x200) >> 9;

int frame_size = 144000*bitrates[bitrate]/mp3_samplerate + padding;

if ( mp3_data_buffer )
free(mp3_data_buffer);
mp3_data_buffer = (u8*)memalign(64, frame_size);

sceIoLseek32(mp3_handle, mp3_data_start, PSP_SEEK_SET); //seek back

if ( sceIoRead( mp3_handle, mp3_data_buffer, frame_size ) != frame_size ) {
fprintf(stderr,"$>sceIoRead frame_size < frame_size exitin \n");
eof = 1;
continue;
}

mp3_data_start += frame_size;

mp3_codec_buffer[6] = (unsigned long)mp3_data_buffer;
if (!bc)
mp3_codec_buffer[8] = (unsigned long)mp3_mix_buffer1;
else
mp3_codec_buffer[8] = (unsigned long)mp3_mix_buffer2;

mp3_codec_buffer[7] = mp3_codec_buffer[10] = frame_size;
mp3_codec_buffer[9] = mp3_sample_per_frame * 4;

int res = sceAudiocodecDecode(mp3_codec_buffer, 0x1002);

if ( res < 0 ) {
fprintf(stderr,"$>sceAudiocodecDecode < 0< (%d) exitin \n", res);
eof = 1;
continue;
}
samplesdecoded = mp3_sample_per_frame;
donext-=1;
if (bc)
bc=0;
else
bc=1;

}

}


int InputThread(SceSize args, void *argp)
{

while(!eof)
{

sceCtrlPeekBufferPositive(&pad, 1);
if( pad.Buttons & PSP_CTRL_TRIANGLE )
{
eof=1;
}
sceKernelDelayThread(1);

}

return 0;
}



void SetupInput( void)
{
SceUID itid = sceKernelCreateThread("Input thread",
InputThread,
0x18, 256 * 1024, PSP_THREAD_ATTR_USER, 0);
if (itid >= 0)
sceKernelStartThread(itid, 0, 0);
}




int main(void)
{

SetupCallbacks();
eof=0;
int result = pspSdkLoadStartModule("flash0:/kd/me_for_vsh.prx", PSP_MEMORY_PARTITION_KERNEL);
fprintf(stderr,"$>me_for_vsh %d\n", result);

result = pspSdkLoadStartModule("flash0:/kd/videocodec.prx", PSP_MEMORY_PARTITION_KERNEL);
fprintf(stderr,"$>videocodec %d\n", result);

result = pspSdkLoadStartModule("flash0:/kd/audiocodec.prx", PSP_MEMORY_PARTITION_KERNEL);
fprintf(stderr,"$>audiocodec %d\n", result);

result = pspSdkLoadStartModule("flash0:/kd/mpegbase.prx", PSP_MEMORY_PARTITION_KERNEL);
fprintf(stderr,"$>mpegbase %d\n", result);

result = pspSdkLoadStartModule("flash0:/kd/mpeg_vsh.prx", PSP_MEMORY_PARTITION_USER);
fprintf(stderr,"$>mpeg_vsh %d\n", result);


SetupInput();
pspSdkFixupImports(result);

sceMpegInit();

mp3_handle = sceIoOpen("ms0:/test.mp3", PSP_O_RDONLY, 0777);
if ( ! mp3_handle )
goto wait;
fprintf(stderr,"$>mp3_handle %d\n", mp3_handle);

mp3_channels = 2; //довольно некрасивое ограничение, ну ладно нам для примера потянет....
mp3_samplerate = 44100; //таже фигня
mp3_sample_per_frame = 1152;

mp3_data_start = sceIoLseek32(mp3_handle, 0, PSP_SEEK_CUR);

memset(mp3_codec_buffer, 0, sizeof(mp3_codec_buffer));

if ( sceAudiocodeCheckNeedMem(mp3_codec_buffer, 0x1002) < 0 )
{
fprintf(stderr,"$>sceAudiocodeCheckNeedMem <0 going to wait \n");
goto wait;
}
if ( sceAudiocodecGetEDRAM(mp3_codec_buffer, 0x1002) < 0 )
{
fprintf(stderr,"$>sceAudiocodecGetEDRAM <0 going to wait \n");
goto wait;
}
mp3_getEDRAM = 1;

if ( sceAudiocodecInit(mp3_codec_buffer, 0x1002) < 0 ) {
fprintf(stderr,"$>sceAudiocodecInit <0 going to wait \n");
goto wait;
}



int channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, 1152, PSP_AUDIO_FORMAT_STEREO);
if (channel < 0)
{
fprintf(stderr,"Error reserving channel\n");
goto wait;
}

bc=0;

donext=0;
int decodth = sceKernelCreateThread("decode thread", decode_thread, 0x8, 0x10000, PSP_THREAD_ATTR_USER, NULL);
if (decodth < 0)
{
fprintf(stderr, "failed create decode thread\n");
goto wait;
}

sceKernelStartThread(decodth, 0, 0);
fprintf(stderr, "decode thread %d\n", decodth);
donext=1;

while (!eof){

donext=1;
if (!bc)
sceAudioOutputBlocking(channel, 0x8000, mp3_mix_buffer1);
else
sceAudioOutputBlocking(channel, 0x8000, mp3_mix_buffer2);
}


wait:

if ( mp3_handle ) {
sceIoClose(mp3_handle);
}
if ( mp3_data_buffer) {
free(mp3_data_buffer);
}
if ( mp3_getEDRAM ) {
sceAudiocodecReleaseEDRAM(mp3_codec_buffer);
}

sceCtrlReadBufferPositive(&input, 1);
while(!(input.Buttons & PSP_CTRL_TRIANGLE))
{
sceKernelDelayThread(10000); // wait 10 milliseconds
sceCtrlReadBufferPositive(&input, 1);
}

sceKernelExitGame();
return 0;
}


/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceKernelExitGame();
return 0;
}


/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid;

cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);

sceKernelSleepThreadCB();

return 0;
}


/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = 0;

thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}

return thid;
} пусть оно и выглядит неказисто зато играет даже VBR. основано на примере с ps2dev, добавлено потоковое декодирование в два типа буфера.

wSlava
02.07.2007, 21:12
Еще бы не помешало знать как сделать паузу, ускоренное проигрывание вперед/назад (перемотка), и т.д. А в остальном все гуд.

добавлено через 50 секунд
А ты писал, что с видео разбирался, есть результаты по этому поводу ?

l3VGV
02.07.2007, 21:35
про остановить, поставить eof в 1 :) перемотка это управление указателем мп3 файла, подробнее сказать затрудняюсь, для не VBR вроде всё просто но надо пробовать. пауза возникнет если не устанавливать donext в 1. тут конечно надо всё переписать на семафоры, но для проги примера и так потянет. я щас озадачился сделать простой движок для проигрывания файлов мр3, мр4 и wav(pcm). вот там всё будет. работы потихоньку ведутся.



докладываю по видео.
есть рабочий пример как разобрать и проиграть pmf, от mp4 отличается как я понял только другим форматом звуковой дорожки. точно также как и тут использует только кишки psp, всё работает очень шустро. архив прилагаю, использовать аккуратно, там cpp, и прочие непонятные вещи, афтор говорит что прога иногда виснет. для генерации pmf файлоф надо качать из торентов UMD tools. эти тулсы Sony confidecial такчто ессно проги с ними потом распространять не получится, надо всётаки добивать мр4 чем и занимаюсь.

на форуме кстати не обозначена ситуация с подобными тулзами. может и упоминать нельзя было?

во нафлудил :bb:

l3VGV
08.07.2007, 15:18
1) прошу переименовать тему в "Играем мр3, мр4(h264), wav(pcm), atrac, aac"

2) простенький пример как играть пцм вав, играется на параметрах консолькой по умолчанию(44.1 кГц частота семплирования, 16бит на семпл), однако не проблема изменить их на выбранный канал благо как извлеч инфу из файла там показано...

следущим примером (аринтеровочно завтра если не разленюсь опять) будет атрас3 и атрак3+.

l3VGV
09.07.2007, 22:07
Пример тово как можно играть атрак/3/3+, однако тожесамое можно делать и проще, но об этом потом.

l3VGV
20.07.2007, 23:55
RC альфа беты версии моей либы для играния звукофф. щас мы умеем играть до 8ми звуков одновременно, в данный момент тока вав, мр3, атрак3/+.
ограничения, тока 16bit 44.1кГц причём атрак и мр3 могут быть тока стерео, вавы=моно и стерео.
особо хочется отметить что не получается добиться одновременново качественного воспроизведения чегото отличного от вава...если же забить болтяру на пожирание ресурсов вечным циклом звуковова потока то всё становится идеально. сие есть парадокс для меня, декодирование слежующего фрейма происходит в 5-6 раз быстрее чем отыграет старый, однако видимо хитрость планировщика потоков велика и управление не возвращается достаточно долго чтобы мы пропустили пару семплов в начале и всё закашлялось. воистину тайна великая есмь. как жаль что не владею я джитсу реверс инженеринга :cray:

юзание, подключить хедер инклудом, в мейк фал добавть -ml.o
сырцы пока не выкладываю ибо уж очень стыдно за внутренний хаос :give_rose:
далее всё просто, в начале гденить лепим mlInit() а потом чтобы чтота проиграть mlPlay("ms0:/test.mp3"), можно также хитрее mlPlayEx("ms0:/test.mp3", тутагромкость, COOP), флажок кооп нужен чтобы звук с темже именем играл даже в том случае если онже уже играет. вот. пока больше нифига не работает, в часности зацикливание и кеширование файлов целиком в память. ибо очень меня качество звука занимает чтобы время тратить на остальное всё.
а да кстати остановка, пауза и резюм тоже не работают пока :p как пропускать заголовок мр3 файла я тоже пока не делал, такчто тут тоже могут некоторые не работать...вот атрак&wav зато работает почти на 100% ибо riff.

вобщем велком, жду отзывов :thank_you:

релиз посвящается вСлаве, да прибудет с ним сила довести ИДЕ до совершенства абсолютного!

l3VGV
28.07.2007, 21:31
Упдейт. теперь играет гладко. полирую всякие мелочи типа пропуска текстов в мр3 :give_rose:

freecod
03.08.2007, 04:22
Что-то у меня последний аттач открывает attachment.php и молчит :\
А вообще очень жду релиза. Может заделаю на на этой базе крутой mp3 плагин =) А то mp3_04f юзает libmad и на некоторых mp3 с низким биптрейтом(?) напоминает пакмана с доса на 4 пентиуме: "Мойадреснедоминеулица,мойадрессоветскийсоюз" :\
Есть идея гениального интерфейса к mp3 плагину =)

l3VGV
05.08.2007, 17:49
во очередная альфа. даже стабильная. даже играет. однако из функция работают тока плей и стоп алл :man_in_love:
в принципе для простеньково плеера хватит.

freecod
06.08.2007, 02:16
Не, выдираем все функции из родного плеера =) Кстати, через апи плеера ID3 (теги) получить можно?

l3VGV
06.08.2007, 09:03
нет. более того он некоторые даже пропускает некорректно...

l3VGV
03.11.2007, 10:25
Времени чтобы уделять его развитию категарически нехватает. пожтому выкладываю полные исходники того что есть на данный момент.

в дальнейшем(читай когда время нарисуется) акцент будете перемещён на поддержку исключительно атрака и мр4 фиксированного фармата. ибо хочу сделать простенькую игрушку а там универсальность ненужна.


http://www.rapidshare.ru/453423

Ilsor
09.08.2008, 10:44
А никто не может рассказать, каким образом на PSP звук вообще запускается и как им управлять? Точнее, меня интересуют вот какие вопросы:
1) Как я понимаю, для работы со звуком создаётся канал. Один канал - один звук. То есть, если я запущу два канала одновременно, то они будут микшироваться и накладываться друг на друга?
2) Команда sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,pspsample,PSP_AUDIO_FORMAT_MONO); принимает в параметре pspsample частоту сигнала или размер буфера мгновенного воспроизведения (т.е. того буфера, в котором происходит микширование)? Я делал int pspsample=PSP_AUDIO_SAMPLE_ALIGN(22050), а потом подавал на sceAudioSetChannelDataLen размер буфера равный pspsample. Вызывал sceAudioOutputBlocking и при воспроизведении возникают "пробелы". Выходит, что это как раз размер буфера микширования. Я правильно понимаю?
3) Если пункт 2 верный, то как можно изменить частоту дискретизации и разрядность звука? Я вот хочу 22050 и 8 бит. Я такой команды не нашёл в pspaudio.h. Или она замаскирована. :)
4) Какой максимальный размер звука можно подавать sceAudioSetChannelDataLen? И вообще, sceAudioOutputBlocking нужен выровненный по 64 байта блок данных или всё равно? В pspaudio.h ничего об этом не сказано, но здесь в примерах я видел, что выделялся выровненный блок.

Просто я написал игрушку и хотел к ней приделать звуковое оформление. Ан нет. Всё не так просто, как в Direct Sound. :(

l3VGV
09.08.2008, 11:19
я пытался понять директ саунд. тут наоборот всё прощее. только нету толковых манов.

1) 1 канал = 1 аппаратный канал в звукочипе. каналы могут иметь разные настройки и аппаратно качественно смешаются на выходе. никто не запрещает сделать 10 софтовых каналов миксовать самому и выдавать в 1 аппаратный. что и сделано в сдл либ и многих других.


2) передается туда частота дискретизации. 44.1К, 20.05К и тп.

3) сделать 8бит невозможно, железка знает тока про 16. те точность не регулируется. на вход всегда подается минимум 4*16. частоту менять можно от 8 до 48.

4) для скорости рекомендую давать кусками по 2-4 килобайта и выше. чем больше кусок тем меньше вероятность кряка. максимум вроде 32. не помню точно. блок выдавать ровный и не из кэша. ато иначе он будет неуправляемый.

Ilsor
09.08.2008, 12:21
Ага. Вот оно как...

Но тогда вот что смущает:

2) передается туда частота дискретизации. 44.1К, 20.05К и тп.

Тогда я не понимаю, почему вот такая вот программа воспроизводит на нормальной скорости test.wav с параметрами 44100x16, даже если я укажу int pspsample=PSP_AUDIO_SAMPLE_ALIGN(11050);


#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspaudiolib.h>
#include <pspaudio.h>

#include <math.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

//----------------------------------------------------------------------------------------
PSP_MODULE_INFO("Sound", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER|THREAD_ATTR_VFPU);


void dump_threadstatus(void);

bool done=false;

int exit_callback(int arg1,int arg2,void *common)
{
done=true;
return(0);
}
void audio_callback(void* buf,unsigned int length,void *userdata)
{
/*
sample_t* ubuf=(sample_t*)buf;
for(unsigned int n=0;n<length;n++)
{
ubuf[n].r=255*(n%2);
ubuf[n].l=255*((int)(n/2));
}
*/
}

int CallbackThread(SceSize args, void *argp)
{
int cbid;
cbid=sceKernelCreateCallback("Exit Callback",exit_callback,NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return(0);
}
int SetupCallbacks(void)
{
int thid = 0;
thid=sceKernelCreateThread("update_thread",CallbackThread,0x11,0xFA0,0,0);
if(thid>=0) sceKernelStartThread(thid, 0, 0);
return(thid);
}
//----------------------------------------------------------------------------------------
//начинаем программу
int main(int argc, char **argv)
{
int n;
int argv_len=strlen(argv[0]);
//формируем имя файла уровня
//отматываем до черты
for(n=argv_len;n>0;n--)
{
if (argv[0][n-1]=='/')
{
argv[0][n]=0;//обрубаем строку
break;
}
}
//устанавливаем обработчики
SetupCallbacks();

pspAudioInit();

sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
SceCtrlData pad;

//получаем канал и устанавливаем его параметры
int pspsample=PSP_AUDIO_SAMPLE_ALIGN(11050);
int channel=sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL,pspsample,PSP_AUDIO_FORMAT_MONO );
if (channel>0)
{
unsigned char *Sound=(unsigned char*)memalign(64,1024*1024*2);
char string[255];
unsigned char *ptr=Sound;
sprintf(string,"%stest.wav",argv[0]);
FILE *file=fopen(string,"rb");
int length=0;
while(1)
{
unsigned char b;
if (fread(&b,1,1,file)<=0) break;
*ptr=b;
ptr++;
length++;
}
fclose(file);
int offset=44;
unsigned char *SampleBuffer=(unsigned char*)malloc(16384);
while(done==false)
{
sceCtrlReadBufferPositive(&pad,1);
if (pad.Buttons&PSP_CTRL_TRIANGLE) break;
while(offset<length)
{
sceCtrlReadBufferPositive(&pad,1);
if (pad.Buttons&PSP_CTRL_TRIANGLE) break;
int sample=16384;
if (length<=offset+sample) sample=length-offset;
sceAudioSetChannelDataLen(channel,sample/2);
memcpy(SampleBuffer,Sound+offset,sample);
sceAudioOutputBlocking(channel,PSP_AUDIO_VOLUME_MAX,SampleBuffer);
offset+=sample;
}
}
free(SampleBuffer);
free(Sound);
sceAudioChRelease(channel);
}
//pspAudioSetChannelCallback(0,audio_callback,NULL);

pspAudioEnd();
//выходим из программы
sceKernelExitGame();
return(0);
}


Как такое может быть, если меняется частота дискретизации?

блок выдавать ровный и не из кэша.

В смысле, не из кэша? А как выдавать из кэша?

Ilsor
09.08.2008, 13:30
И ещё есть занятная проблема. В audio_callback, как я понимаю, нужно заполнять буфер с разделением на правый и левый каналы? Даже если звук моно?

Ilsor
10.08.2008, 18:53
Ну вот, сделал-таки библиотеку для запуска звуков в играх. :)

Ilsor
15.08.2008, 18:46
Представляю мой вариант звуковой библиотеки для игр. Она, впрочем, не позволит играть длительные музыкальные фрагменты, так как все звуки находятся в памяти постоянно.
Итак, как ей пользоваться.
0) Обработкой звука занимается класс CSound, при этом объект cSound создан по умолчанию.
1) Создать функцию обратного вызова:
void audio_callback(void* buf,unsigned int length,void *userdata)
{
cSound.CallBack(buf,length,userdata);
}
2) Привязать эту функцию к классу:
cSound.SetCallBackFunction(audio_callback);
3) Загрузить звук:
cSound.LoadNewSound(FileName,0);//загружаем звуковой файл
0 - это индентификатор звука, т.е. по этому номеру с данным звуком можно будет работать, разумеется, это любое удобное вам число.
4) Запустить звук на выполнение:
cSound.Play(0);

Всё. Одновременно звуков можно запускать довольно много. Т.е. это именно то, что нужно для игры.

Ах да, файлы звуков в собственном примитивном формате - заголовок-длина и сами незапакованные данные. Этот формат делает прилагаемая программа из несжатых wav-файлов с параметрами 44100 на 16 бит, моно. Но это можно переделать при желании.

l3VGV
15.08.2008, 18:57
сколько памяти займет 5минутный фоновый трек?

Ilsor
15.08.2008, 21:33
44100(частота)x2(байт на выборку)x5(минут)x60 (по 60 секнуд в минуте)= 26 мегабайт в файле и в два раза больше в памяти (т.к. стерео). Их нужно подгружать потихоньку. :)

l3VGV
16.08.2008, 00:02
собсно в догонку. зачем свой формат если есть вав?
ух. там ещё и ооп. мур. я такова не понимаю пока :)

Ilsor
16.08.2008, 08:20
собсно в догонку. зачем свой формат если есть вав?

WAV,увы, в общем случае читать не так-то просто, как это получилось у тебя. Там не просто заголовок нужно пропустить. Он основан на формате IFF (формат взаимного файлового обмена) и Microsoft даже пришлось написать специальный набор функций для чтения wav-файлов в составе MMIO (интерфейс ввода-вывода мультимедиа). А на PSP я такого не видел пока. Потому и пришёл к выводу, что лучше воспользоваться Windows и конвертнуть в прямые аудиоданные, чем разбирать контейнеры IFF.

там ещё и ооп. мур.

А что такое мур.?

l3VGV
16.08.2008, 11:24
вроде простой контейнер. но не суть.
вперёд разбиратся с огг :) и импульсными треками.