libFLAC seeking problem, please help!(Solved, Code Included)

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
liberty
Posts: 33
Joined: Wed Sep 16, 2009 11:30 am

libFLAC seeking problem, please help!(Solved, Code Included)

Post by liberty »

Here is my FLAC player based on the code in this forum:

Code: Select all

#include <pspkernel.h>
#include <pspctrl.h>
#include <pspdebug.h>
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <psppower.h>
#include <pspdisplay.h>
#include <string.h>
#include <stdio.h>

//#include <tremor/ivorbiscodec.h>
//#include <tremor/ivorbisfile.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>

#include <FLAC/stream_decoder.h>

#define printf pspDebugScreenPrintf
#define OUTPUT_BUFFER 32768
PSP_MODULE_INFO&#40;"Cueplayer", 0, 1, 0&#41;;
PSP_MAIN_THREAD_ATTR&#40;PSP_THREAD_ATTR_USER|PSP_THREAD_ATTR_VFPU&#41;;
//PSP_HEAP_SIZE_MAX&#40;&#41;;
PSP_HEAP_SIZE_KB&#40;-256&#41;;

//Semaphores
static SceUID buffer_empty_sema;
static SceUID buffer_full_sema;

//global flags
static int running_flag = 0;
static int eos_flag = 0;

//global parameters and data
static int audio_vol = 0x4000; // 1/2 max volume
static FLAC__uint64 total_samples = 0;
static unsigned int sample_rate = 0;
static unsigned int bps = 0;
static unsigned int channels = 0;
static int buffer_flip = 0;
static char pcmout1&#91;OUTPUT_BUFFER&#93;;
static char pcmout2&#91;OUTPUT_BUFFER&#93;;
static long pcmlen1;
static long pcmlen2;
static FILE* fileptr;
static int audio_channel = 0;

FLAC__StreamDecoder* decoder = NULL;
FLAC__StreamDecoderInitStatus init_status;

//Common Routines

/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41; &#123;
   sceKernelExitGame&#40;&#41;;
   return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41; &#123;
   int cbid;

   cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
   sceKernelRegisterExitCallback&#40;cbid&#41;;
   sceKernelSleepThreadCB&#40;&#41;;
   return 0;
&#125;

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41; &#123;
   int thid = 0;

   thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0&#41;;
   if&#40;thid >= 0&#41; &#123;
      sceKernelStartThread&#40;thid, 0, 0&#41;;
   &#125;

   return thid;
&#125;
//FLAC decoding callbacks
//required by
//FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file&#40;       
//      FLAC__StreamDecoder *        decoder,
//      const char *    filename,
//      FLAC__StreamDecoderWriteCallback    write_callback,
//      FLAC__StreamDecoderMetadataCallback     metadata_callback,
//      FLAC__StreamDecoderErrorCallback    error_callback,
//      void *      client_data
//      &#41;   

FLAC__StreamDecoderWriteStatus write_callback&#40;const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer&#91;&#93;, void* client_data&#41;
&#123;
    const FLAC__uint32 total_size = &#40;FLAC__uint32&#41;&#40;total_samples * channels * &#40;bps / 8&#41;&#41;;
    FLAC__int16* fillbuf;
    int i;

    &#40;void&#41;decoder, &#40;void&#41;client_data;


    if&#40;total_samples == 0&#41;&#123;
        printf&#40;"Error total samples is 0??\n"&#41;;
        return -1;
    &#125;

    if&#40;channels != 2 || bps != 16&#41;&#123;
        printf&#40;"Error Only support 16bit and 2 channel\n"&#41;;
        return -1;
    &#125;
    sceKernelWaitSema&#40;buffer_empty_sema, 1, 0&#41;;
    printf&#40;"B"&#41;;
    fillbuf = buffer_flip ? &#40;FLAC__int16*&#41;pcmout2 &#58; &#40;FLAC__int16*&#41;pcmout1;

    for&#40;i = 0; i < frame -> header.blocksize; i++&#41;&#123;
        // fill 2 channel into odd and even continuous fillbuf
        fillbuf&#91;i << 1&#93; = &#40;FLAC__int16&#41;buffer&#91;0&#93;&#91;i&#93;;
        fillbuf&#91;&#40;i << 1&#41; + 1&#93; = &#40;FLAC__int16&#41;buffer&#91;1&#93;&#91;i&#93;;
    &#125;
    if&#40;buffer_flip&#41;&#123;
        pcmlen2 = frame -> header.blocksize << 2;
    &#125;
    else&#123;
        pcmlen1 = frame -> header.blocksize << 2;
    &#125;
    
    sceKernelSignalSema&#40;buffer_full_sema, 1&#41;;
    
    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
&#125;

void metadata_callback&#40;const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata* metadata, void* client_data&#41;
&#123;
    &#40;void&#41;decoder, &#40;void&#41;client_data;
    if&#40;metadata -> type == FLAC__METADATA_TYPE_STREAMINFO&#41;&#123;
        total_samples = metadata -> data.stream_info.total_samples;
        sample_rate = metadata -> data.stream_info.sample_rate;
        channels = metadata -> data.stream_info.channels;
        bps = metadata -> data.stream_info.bits_per_sample;
    &#125;
&#125;

void error_callback&#40;const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data&#41;
&#123;
    &#40;void&#41;decoder, &#40;void&#41;client_data;
    printf&#40;"Error callback invoked&#58; %s!\n", FLAC__StreamDecoderErrorStatusString&#91;status&#93;&#41;;
&#125;

//Output audio thread

int audio_output&#40;SceSize args, void* argp&#41;
&#123;
    int playlen;
    char* playbuf;
    while&#40;running_flag&#41;&#123;
        sceKernelWaitSema&#40;buffer_full_sema, 1, 0&#41;;
        printf&#40;"A"&#41;;
        if&#40;eos_flag || !running_flag&#41;&#123;
            break;
        &#125;
        playlen = buffer_flip ? pcmlen1 &#58; pcmlen2;
        playbuf = buffer_flip ? pcmout1 &#58; pcmout2;
        buffer_flip ^= 1;
        sceKernelSignalSema&#40;buffer_empty_sema, 1&#41;;
        sceAudioSetChannelDataLen&#40;audio_channel, playlen / 4&#41;;
        sceAudioOutputBlocking&#40;audio_channel, audio_vol, playbuf&#41;;
    &#125;
    sceKernelExitDeleteThread&#40;0&#41;;
    return 0;
&#125;


//FLAC playing Main function
int playflac&#40;char* filename&#41;
&#123;
    //SceUID sceKernelCreateSema    &#40;   const char *     name,
    //                                  SceUInt     attr,
    //                                  int     initVal,
    //                                  int     maxVal,
    //                                  SceKernelSemaOptParam *     option   
    //                                  &#41;   

    SceUID audio_thid;
    fileptr = fopen&#40;filename, "rb"&#41;;
    
    buffer_empty_sema = sceKernelCreateSema&#40;"buffer_empty_sema", 0, 1, 1, 0&#41;;
    buffer_full_sema = sceKernelCreateSema&#40;"buffer_full_sema", 0, 0, 1, 0&#41;;
    
    if&#40;&#40;decoder = FLAC__stream_decoder_new&#40;&#41;&#41; == NULL&#41;&#123;
        printf&#40;"cannot create flac stream decoder!\n"&#41;;
        sceKernelDelayThread&#40;2*1000*1000&#41;;
        return -1;
    &#125;
    init_status = FLAC__stream_decoder_init_file&#40;decoder, filename, write_callback, metadata_callback, error_callback, fileptr&#41;;
    if&#40;init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK&#41;&#123;
        printf&#40;"Init decoder error\n"&#41;;
        fclose&#40;fileptr&#41;;
        return -1;
    &#125;
    memset&#40;pcmout1, 0, OUTPUT_BUFFER&#41;;
    memset&#40;pcmout2, 0, OUTPUT_BUFFER&#41;;
    pcmlen1 = 0;
    pcmlen2 = 0;
    eos_flag = 0;
    running_flag = 1;
    sceKernelSignalSema&#40;buffer_empty_sema, 1&#41;;
    sceKernelSignalSema&#40;buffer_full_sema, 0&#41;;
    audio_channel = sceAudioChReserve&#40;audio_channel, OUTPUT_BUFFER / 4, PSP_AUDIO_FORMAT_STEREO&#41;;
    audio_thid = sceKernelCreateThread&#40;"audio_output", audio_output, 0x16, 0x1800, PSP_THREAD_ATTR_USER, NULL&#41;;
    if&#40;audio_thid < 0&#41;&#123;
        printf&#40;"audio thread creation error!\n"&#41;;
        return -1;
    &#125;
    sceKernelStartThread&#40;audio_thid, 0, NULL&#41;;
    if&#40;FLAC__stream_decoder_process_until_end_of_stream&#40;decoder&#41;&#41;&#123;
        printf&#40;"SUCCESS END OF STREAM.\n"&#41;;
        FLAC__stream_decoder_delete&#40;decoder&#41;;
        fclose&#40;fileptr&#41;;
        running_flag = 0;
        sceKernelSignalSema&#40;buffer_empty_sema, 1&#41;;
        sceKernelSignalSema&#40;buffer_full_sema, 1&#41;;
        sceKernelDelayThread&#40;1000 * 1000&#41;;
        sceAudioChRelease&#40;audio_channel&#41;;
        sceKernelDelayThread&#40;1000 * 1000&#41;;
        return 0;
    &#125;
    else&#123;
        printf&#40;"Failed!\n"&#41;;
        return -1;
    &#125;
&#125;    

int player_control&#40;SceSize args, void* argp&#41;
&#123;
    SceCtrlData pad;
    while&#40;1&#41;&#123;
        sceKernelDelayThread&#40;1000*500&#41;;
        sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
        if&#40;pad.Buttons & PSP_CTRL_CROSS&#41;&#123;
            printf&#40;"hihi\n"&#41;;
            sceKernelDelayThread&#40;1000*20&#41;;
            FLAC__stream_decoder_seek_absolute&#40;decoder, 44100*30&#41;;
            FLAC__stream_decoder_reset&#40;decoder&#41;;
            sceKernelDelayThread&#40;1000*20&#41;;
            

        &#125;
    &#125;

    return 0;
&#125;


int main&#40;&#41;
&#123;
    char* filename = "ms0&#58;/psp/music/b.flac";
    pspDebugScreenInit&#40;&#41;;
    SceUID pc_thid;
    SetupCallbacks&#40;&#41;;
    pc_thid = sceKernelCreateThread&#40;"player_control", player_control, 0x11, 0x1800, PSP_THREAD_ATTR_USER, NULL&#41;;
    if&#40;pc_thid > 0&#41;&#123;
        sceKernelStartThread&#40;pc_thid, 0, 0&#41;;
    &#125;
    else&#123;
        printf&#40;"player_control thread error\n"&#41;;
    &#125;
    printf&#40;"playing!........"&#41;;
    playflac&#40;filename&#41;;
    sceKernelExitGame&#40;&#41;;
    return 0;
&#125;
This function contains the seeking part:
player_control().
using this function.
FLAC__stream_decoder_seek_absolute(decoder, 44100 * 30);


The music is more than 3 minutes that is more than 8000000 samples.

The player can play music correctly but when it invoke "FLAC__stream_decoder_seek_absolute", the whole system halts.

No matter where I add the FLAC__stream_decoder_seek_absolute function, the system will halt when invoking this function.

Forget to mention, I am using the latest SVN SDK in Linux and libflac 1.2.1. And I have found the lightmp3 can do the seeking using the same function correctly.

Anyone know how to solve this problem? Thank you very much!
Last edited by liberty on Fri Sep 18, 2009 11:00 am, edited 1 time in total.
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

Why did you open the file to to nothing with it?

Code: Select all

FLAC__stream_decoder_process_until_end_of_stream&#40;decoder&#41;;
I think you are trying to seek while decoding
Try a loop with FLAC__stream_decoder_process_single(decoder) and pause the decoding when you want to seek.
liberty
Posts: 33
Joined: Wed Sep 16, 2009 11:30 am

Post by liberty »

psPea wrote:Why did you open the file to to nothing with it?

Code: Select all

FLAC__stream_decoder_process_until_end_of_stream&#40;decoder&#41;;
I think you are trying to seek while decoding
Try a loop with FLAC__stream_decoder_process_single(decoder) and pause the decoding when you want to seek.
I added the pause function, but it does not solve the problem. The system still halt.
Modified player control function

Code: Select all

            player_paused = 1;
            sceKernelDelayThread&#40;1000*20&#41;;
            FLAC__stream_decoder_seek_absolute&#40;decoder, 20 * 44100&#41;;
            printf&#40;"OK?"&#41;; // The program never reach here
            sceKernelDelayThread&#40;1000*20&#41;;
            player_paused = 0; 

Modified write callback:

Code: Select all

    sceKernelStartThread&#40;audio_thid, 0, NULL&#41;;
    while&#40;1&#41;&#123;
        if&#40;player_paused == 1&#41;&#123;
            sceKernelDelayThread&#40;5 * 1000&#41;;

            continue;
        &#125;
        decoding_status = FLAC__stream_decoder_process_single&#40;decoder&#41;;
        if&#40;decoding_status == 0&#41;&#123;
            break;
        &#125;

    &#125;
    end_decoder&#40;&#41;;
    return 0;

The FLAC__stream_decoder_seek_absolute function cannot be corrected excuted.


You mean that the file opening is this one:
fileptr = fopen(filename, "rb"); ?

It is because the
init_status = FLAC__stream_decoder_init_file(decoder, filename, write_callback, metadata_callback, error_callback, fileptr);
need this fileptr. It is the source of the data stream.
sakya
Posts: 190
Joined: Fri Apr 28, 2006 5:48 pm
Contact:

Post by sakya »

Hi! :)

You need to replace the FLAC__stream_decoder_process_until_end_of_stream with FLAC__stream_decoder_process_single in a loop.

Something like:

Code: Select all

while &#40;FLAC__stream_decoder_process_single&#40;decoder&#41; != false&#41;&#123;
    //Write here the code using FLAC__stream_decoder_seek_absolute
    if &#40;FLAC__stream_decoder_get_state&#40;decoder&#41; == FLAC__STREAM_DECODER_END_OF_STREAM &#41;
        break;
&#125;
EDIT: Sorry I see now you did it...and cannot delete post :)

Ciaooo
Sakya
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

>It is because the
init_status = FLAC__stream_decoder_init_file(decoder, filename, write_callback, metadata_callback, error_callback, fileptr);
need this fileptr. It is the source of the data stream

No. See here.

I meant replace FLAC__stream_decoder_process_until_end_of_stream with FLAC__stream_decoder_process_single in a loop and when you want to seek
pause the decoding i.e. stop calling FLAC__stream_decoder_process_single
also I don't think you should call FLAC__stream_decoder_process_single in the write callback

Your pause code doesn't guarantee that FLAC__stream_decoder_process_single isn't still executing, you'll have to use a more sophisticated method than that.

You can see a working flac player code with seek here, check AudioFLAC.c.
liberty
Posts: 33
Joined: Wed Sep 16, 2009 11:30 am

Post by liberty »

psPea wrote:>


Your pause code doesn't guarantee that FLAC__stream_decoder_process_single isn't still executing, you'll have to use a more sophisticated method than that.
First, I don't mean in write callback, It is in the playflac function.

And you hit right in the bulleye of my problem. The problem occurs when I start seeking, the FLAC__stream_decoder_process_single is still executing! Thank you very much!
Just one more question, What does the void * client_data really mean?

Also thanks sakya, I modify the code from your example. It is working now.
Here is modified part.

in playflac function.

Code: Select all

    sceKernelStartThread&#40;audio_thid, 0, NULL&#41;;
    while&#40;1&#41;&#123;
        if&#40;player_paused == 1&#41;&#123;
            sceKernelDelayThread&#40;5 * 1000&#41;;

            continue;
        &#125;

        if&#40;seek_flag&#41;&#123;
            FLAC__stream_decoder_seek_absolute&#40;decoder, 60 * 44100&#41;;
            seek_flag = 0;
        &#125;
        
        decoding_status = FLAC__stream_decoder_process_single&#40;decoder&#41;;
        if&#40;decoding_status == 0&#41;&#123;
            break;
        &#125;

    &#125;
    end_decoder&#40;&#41;;
I add a seek_flag here.
And then in player_control:

Code: Select all

        if&#40;pad.Buttons & PSP_CTRL_CROSS&#41;&#123;
            seek_flag = 1;
            sceKernelDelayThread&#40;1000*20&#41;;
        &#125;
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

You could set your seek flag to the value you wish it to seek to. That would eliminate an extra variable.
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

>Just one more question, What does the void * client_data really mean?

Its just a value you can pass to the callbacks, it can be anything want.
Just typecast as needed.
liberty
Posts: 33
Joined: Wed Sep 16, 2009 11:30 am

Post by liberty »

J.F. wrote:You could set your seek flag to the value you wish it to seek to. That would eliminate an extra variable.
Yes, it is good suggestion.
Post Reply