Exemplo n.º 1
0
static OMX_ERRORTYPE
mp3d_proc_stop_and_return (void * ap_obj)
{
  mp3d_prc_t * p_obj = ap_obj;
  char buffer[80];
  assert (ap_obj);
  mad_timer_string (p_obj->timer_, buffer, "%lu:%02lu.%03u", MAD_UNITS_MINUTES,
                    MAD_UNITS_MILLISECONDS, 0);
  TIZ_TRACE (handleOf (p_obj), "%lu frames decoded (%s)", p_obj->frame_count_,
             buffer);
  /* NOTE: de-init the decoder here, as there seems to be no obvious flush
     functionality that could be used instead */
  deinit_mad_decoder (ap_obj);
  return release_headers (p_obj, OMX_ALL);
}
Exemplo n.º 2
0
void GetTimeString(char *dest) {
    mad_timer_string(timer, dest, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0);
};
Exemplo n.º 3
0
enum mad_flow read_header(void *data, struct mad_header const * header)
{
    char long_currenttime_str[14]; /* this *will* fill if you're using 100000+ minute mp3s */
    char long_remaintime_str[14];
    static int frames_played = 0;
    
    buffer *playbuf = (buffer *)data;
    mad_timer_t time_remaining;
    char *ao_time;

    if (stop_playing_file)
    {
        stop_playing_file = 0;
        status = MPG321_STOPPED;
        return MAD_FLOW_STOP;
    }
    
    if(options.opt & MPG321_REMOTE_PLAY)
    {
        enum mad_flow mf;

        /* We might have to stop if the user inputs something */
        if ((mf = remote_get_input_nowait(playbuf)))
            return mf;
    }

    /* Stop playing if -n is used, and we're at the frame specified. */
    if ((playbuf->max_frames != -1) && (frames_played++ > playbuf->max_frames))
    {
        frames_played = 0;
        status = MPG321_STOPPED;
	if(options.opt & MPG321_ENABLE_BUFFER) Decoded_Frames->done = 1;
	//fprintf(stderr,"Total D: %d\n",Decoded_Frames->total_decoded_frames);
        return MAD_FLOW_STOP;
    }

    current_frame++;

    mad_timer_add(&current_time, header->duration);

    if(options.opt & MPG321_USE_SCROBBLER && scrobbler_time > 0 && scrobbler_time < current_time.seconds)
    {
	    scrobbler_time = -1;
	    scrobbler_report();
    }

    if(options.opt & (MPG321_VERBOSE_PLAY | MPG321_REMOTE_PLAY))
    {
        mad_timer_string(current_time, long_currenttime_str, "%.2u:%.2u.%.2u", MAD_UNITS_MINUTES,
                            MAD_UNITS_CENTISECONDS, 0);

        if (mad_timer_compare(playbuf->duration, mad_timer_zero) == 0)
            time_remaining = current_time;
        else
            time_remaining = playbuf->duration;


        mad_timer_negate(&current_time);

        mad_timer_add(&time_remaining, current_time);
        mad_timer_negate(&current_time);

        mad_timer_string(time_remaining, long_remaintime_str, "%.2u:%.2u.%.2u", MAD_UNITS_MINUTES,
                            MAD_UNITS_CENTISECONDS, 0);
    }
                        
    /* update cached table of frames & times */
    if (current_frame <= playbuf->num_frames) /* we only allocate enough for our estimate. */
    {
        playbuf->frames[current_frame] = playbuf->frames[current_frame-1] + (header->bitrate / 8 / 1000)
            * mad_timer_count(header->duration, MAD_UNITS_MILLISECONDS);
        playbuf->times[current_frame] = current_time;
    }
    
    if (file_change)
    {
        file_change = 0;
        if (options.opt & MPG321_REMOTE_PLAY)
        {
            printf("@S %s %d %d %s %d %ld %d %d %d %d %ld %d\n",versionstring(header->flags), header->layer, header->samplerate,
                modestringucase(header->mode), header->mode_extension, 
                (header->bitrate / 8 / 100) * mad_timer_count(header->duration, MAD_UNITS_CENTISECONDS),
                MAD_NCHANNELS(header), header->flags & MAD_FLAG_COPYRIGHT ? 1 : 0, 
                header->flags & MAD_FLAG_PROTECTION ? 1 : 0, header->emphasis,
                header->bitrate/1000, header->mode_extension);
        }    

        else if (options.opt & MPG321_VERBOSE_PLAY)/*zip it good*/
        {
            fprintf(stderr, "MPEG %s, Layer: %s, Freq: %d, mode: %s, modext: %d, BPF : %ld\n"
                    "Channels: %d, copyright: %s, original: %s, CRC: %s, emphasis: %d.\n"
                    "Bitrate: %ld Kbits/s, Extension value: %d\n"
                    "Audio: 1:1 conversion, rate: %d, encoding: signed 16 bit, channels: %d\n",
                    versionstring(header->flags),layerstring(header->layer), header->samplerate, modestringucase(header->mode), header->mode_extension, 
                    (header->bitrate / 100) * mad_timer_count(header->duration, MAD_UNITS_CENTISECONDS),
                    MAD_NCHANNELS(header), header->flags & MAD_FLAG_COPYRIGHT ? "Yes" : "No",
                    header->flags & MAD_FLAG_ORIGINAL ? "Yes" : "No", header->flags & MAD_FLAG_PROTECTION ? "Yes" : "No",
                    header->emphasis, header->bitrate/1000, header->mode_extension,
                    header->samplerate, MAD_NCHANNELS(header));
        }

        else if (!(options.opt & MPG321_QUIET_PLAY))/*I love Joey*/
        {
            fprintf(stderr, "MPEG %s layer %s, %ld kbit/s, %d Hz %s\n",
                versionstring(header->flags),layerstring(header->layer), header->bitrate/1000, header->samplerate, modestring(header->mode));
        }
    }
    
    if (status == MPG321_SEEKING && options.seek)
    {
        if (!--options.seek)
            status = MPG321_PLAYING;

        return MAD_FLOW_IGNORE;
    }
    else
    {
        status = MPG321_PLAYING;
    }

    if(!(options.opt & MPG321_ENABLE_BUFFER))
    {
	    if(count > 0)
	    {
		    count++;
		    if(count > 40)
		    {
			    if(!(options.opt & MPG321_VERBOSE_PLAY))
				    fprintf(stderr,"                \r");
			    count = -1;
			    fflush(stderr);
		    }
	    }
    }

    if(options.opt & MPG321_ENABLE_BUFFER)
    {
	    ao_time = (Output_Queue+mad_decoder_position)->time;
	    (Output_Queue+mad_decoder_position)->num_frames = playbuf->num_frames - current_frame;
	    if(Decoded_Frames->is_file) (Output_Queue+mad_decoder_position)->seconds = time_remaining.seconds;
    }

    if (options.opt & MPG321_VERBOSE_PLAY)
    {
        if (!options.skip_printing_frames 
            || (options.skip_printing_frames && !(current_frame % options.skip_printing_frames)))
   
	      	if(count > 0)
		{
/*			if(options.opt & MPG321_ENABLE_BUFFER)
			{	
				sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame,
					playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
				//sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s], \r", current_frame,
				//	playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
				//sprintf(ao_time, "Volume: %d%%  Frame# %5lu [%5lu], Time: %s [%s], \r",volume, current_frame,
				//	playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
			}else*/
			{
				fprintf(stderr, "Volume: %d%%  Frame# %5lu [%5lu], Time: %s [%s], \r",volume, current_frame,
					playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
			}
		}
		else if(count < 0)
		{
			if(options.opt & MPG321_ENABLE_BUFFER)
			{
//				sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s],                     \r", current_frame,
				sprintf(ao_time, "Frame# %5lu [%5lu], Time: %s [%s],                 \r", current_frame,
					playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
			}
			else
			{
				
				fprintf(stderr, "Frame# %5lu [%5lu], Time: %s [%s],                      \r", current_frame,
					playbuf->num_frames > 0 ? playbuf->num_frames - current_frame : 0, long_currenttime_str, long_remaintime_str);
			}
		}
    }
    else if (options.opt & MPG321_REMOTE_PLAY)
    {
    
	    if (!options.skip_printing_frames 
            || (options.skip_printing_frames && !(current_frame % options.skip_printing_frames)))
	    {
		    if(options.opt & MPG321_ENABLE_BUFFER)
		    {
			    sprintf(ao_time,"@F %ld %ld %.2f %.2f\n", current_frame, playbuf->num_frames - current_frame,
				    	    ((double)mad_timer_count(current_time, MAD_UNITS_CENTISECONDS)/100.0),
			    		    ((double)mad_timer_count(time_remaining, MAD_UNITS_CENTISECONDS)/100.0));
		    }
		    else
		    {

			    fprintf(stderr,"@F %ld %ld %.2f %.2f\n", current_frame, playbuf->num_frames - current_frame,
				    	    ((double)mad_timer_count(current_time, MAD_UNITS_CENTISECONDS)/100.0),
			    		    ((double)mad_timer_count(time_remaining, MAD_UNITS_CENTISECONDS)/100.0));
		    }
	    }
    }
    return MAD_FLOW_CONTINUE;
}        
Exemplo n.º 4
0
static void 
MP3_getInfo()
{
    int FrameCount = 0;
    struct mad_stream stream;
    struct mad_header header; 
    mad_stream_init (&stream);
    mad_header_init (&header);

    MP3_info.fileSize = size;
    mad_timer_reset(&MP3_info.length);
    mad_stream_buffer (&stream, mp3_data, size);
    while (1){
        if (mad_header_decode (&header, &stream) == -1){
            if (MAD_RECOVERABLE(stream.error)){
                continue;                
            }else{
                break;
            }
        }
        //Informazioni solo dal primo frame:
        if (FrameCount == 0){
            switch (header.layer) {
            case MAD_LAYER_I:
                strcpy(MP3_info.layer,"I");
                break;
            case MAD_LAYER_II:
                strcpy(MP3_info.layer,"II");
                break;
            case MAD_LAYER_III:
                strcpy(MP3_info.layer,"III");
                break;
            default:
                strcpy(MP3_info.layer,"unknown");
                break;
            }

            MP3_info.kbit = header.bitrate / 1000;
            MP3_info.hz = header.samplerate;
            switch (header.mode) {
            case MAD_MODE_SINGLE_CHANNEL:
                strcpy(MP3_info.mode, "single channel");
                break;
            case MAD_MODE_DUAL_CHANNEL:
                strcpy(MP3_info.mode, "dual channel");
                break;
            case MAD_MODE_JOINT_STEREO:
                strcpy(MP3_info.mode, "joint (MS/intensity) stereo");
                break;
            case MAD_MODE_STEREO:
                strcpy(MP3_info.mode, "normal LR stereo");
                break;
            default:
                strcpy(MP3_info.mode, "unknown");
                break;
            }

            switch (header.emphasis) {
            case MAD_EMPHASIS_NONE:
                strcpy(MP3_info.emphasis,"no");
                break;
            case MAD_EMPHASIS_50_15_US:
                strcpy(MP3_info.emphasis,"50/15 us");
                break;
            case MAD_EMPHASIS_CCITT_J_17:
                strcpy(MP3_info.emphasis,"CCITT J.17");
                break;
            case MAD_EMPHASIS_RESERVED:
                strcpy(MP3_info.emphasis,"reserved(!)");
                break;
            default:
                strcpy(MP3_info.emphasis,"unknown");
                break;
            }            
        }
        FrameCount++;
        mad_timer_add (&MP3_info.length, header.duration);
    }
    mad_header_finish (&header);
    mad_stream_finish (&stream);

    MP3_info.frames = FrameCount;
    mad_timer_string(MP3_info.length, MP3_info.strLength, "%02lu:%02u:%02u", MAD_UNITS_HOURS, MAD_UNITS_MILLISECONDS, 0);
}
Exemplo n.º 5
0
int main(int argc, char *argv[])
{
    int fd = 0;
    char *currentfile, old_dir[PATH_MAX];
    playlist *pl = NULL;
    struct id3_file *id3struct = NULL;
    struct id3_tag *id3tag = NULL;
    int retval;

    buffer playbuf;
    
    struct mad_decoder decoder;
    pthread_t keyb_thread;

    key_t sem_key;
    key_t mem_key;
    key_t frames_key;

    union semun sem_ops;
    int shm_id;
    int frames_id;
    mad_decoder_position = 0;
    output_buffer_position = 0;
    
    old_dir[0] = '\0';

    playbuf.pl = pl = new_playlist();

    if (!pl)
    {
        fprintf(stderr, "malloc failed at startup!\n");
        exit(1);
    }

    loop_remaining = 1;

    options.volume = MAD_F_ONE;

    status = MPG321_PLAYING;
    
    /* Get the command line options */
    parse_options(argc, argv, pl);

    if(options.opt & MPG321_PRINT_FFT)
	    if(!(options.opt & MPG321_REMOTE_PLAY))
	    {
		    /* printf("FFT analysis can only be used in Remote mode play.\n\n"); */
		    usage(argv[0]);			
		    exit(0);
	    }


    /* If there were no files and no playlist specified just print the usage */
    if (!playlist_file && optind == argc)
    {
        usage(argv[0]);
        exit(0);
    }

    if (playlist_file)
        load_playlist(pl, playlist_file);

    if(options.opt & MPG321_RECURSIVE_DIR)
	    add_cmdline_files_recursive_dir(pl, argv);
    else
	    add_cmdline_files(pl, argv);

    if (shuffle_play)
        shuffle_files(pl);

    if(options.opt & MPG321_ENABLE_BUFFER)
    {
	    /* Initialize semaphore and shared memeory */
	    if(access(argv[0],X_OK) == 0)
		    sem_key = ftok(argv[0],0);
	    else
		    sem_key = ftok(MPG321_PATH,0);
	    if(sem_key == -1)
	    {
		    perror("Cannot obtain resources for semaphores");
		    exit(EXIT_FAILURE);
	    }
	    semarray = semget(sem_key,3,IPC_CREAT | IPC_EXCL | S_IRWXU);
	    if(semarray == -1)
	    {
		    perror("Cannot initialize semaphores");
		    exit(EXIT_FAILURE);
	    }
	    sem_ops.val = buffer_size-1;
	    if(semctl(semarray,0,SETVAL,sem_ops) == -1)
	    {
		    perror("Error while initializing mad_decoder semaphore");
		    if(semctl(semarray,0,IPC_RMID) == -1)
			    perror("Error while destroying semaphores");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    sem_ops.val = 0;
	    if(semctl(semarray,1,SETVAL,sem_ops) == -1)
	    {
		    perror("Error while initializing mad_decoder semaphore");
		    if(semctl(semarray,0,IPC_RMID) == -1)
			    perror("Error while destroying semaphores");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    sem_ops.val = 0;
	    if(semctl(semarray,2,SETVAL,sem_ops) == -1)
	    {
		    perror("Error while initializing mad_decoder semaphore");
		    if(semctl(semarray,0,IPC_RMID) == -1)
			    perror("Error while destroying semaphores");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }

	    /* Shared Memory */
	    mem_key = ftok(argv[0],1);
	    shm_id = shmget(mem_key,buffer_size * sizeof(output_frame), IPC_CREAT | S_IREAD | S_IWRITE);
	    if(shm_id == -1)
	    {
		    perror("Cannot initialize shared buffer");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    Output_Queue = shmat(shm_id,NULL,0);
	    if(*(int *)Output_Queue == -1)
	    {
		    perror("Error while attaching shared buffer to mad_decoder");
		    if(shmctl(shm_id,IPC_RMID,NULL))
			    perror("Cannot destroy shared buffer");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    static int n;
	    for(n=0;n<buffer_size;n++)
	    {
		    memset((Output_Queue+n)->data,'\0',4608);
		    memset((Output_Queue+n)->time,'\0',80);
		    (Output_Queue+n)->length = 0;
		    (Output_Queue+n)->seconds = 0;
		    (Output_Queue+n)->num_frames = 0;
	    }
	    
	    frames_key = ftok(argv[0],2);
	    frames_id = shmget(frames_key,buffer_size * sizeof(decoded_frames), IPC_CREAT | S_IREAD | S_IWRITE);
	    if(frames_id == -1)
	    {
		    perror("Cannot initialize shared frames counter");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    Decoded_Frames = shmat(frames_id,NULL,0);
	    if(*(int *)Decoded_Frames == -1)
	    {
		    perror("Error while attaching shared frames counter to mad_decoder");
		    if(shmctl(frames_id,IPC_RMID,NULL))
			    perror("Cannot destroy shared frames counter");
		    goto out;
		    //exit(EXIT_FAILURE);
	    }
	    	
	    Decoded_Frames->is_http = 0;
	    Decoded_Frames->is_file = 0;

    }
    else {
	    ao_initialize();
	    check_default_play_device();
    }
    
    if (!(options.opt & MPG321_REMOTE_PLAY))
    {
        handle_signals(-1); /* initialize signal handler */
        remote_input_buf[0] = '\0';
    }
    
    if (!(options.opt & MPG321_QUIET_PLAY)) 
        mpg123_boilerplate();
    
    if (options.opt & MPG321_REMOTE_PLAY)
    {
        printf ("@R MPG123\n");
	if(options.opt & MPG321_ENABLE_BUFFER)
	{
#ifdef HAVE_ALSA
		init_alsa_volume_control("default"); /* For the moment use "default", it works on most of the systems. Tested in Debian,Fedora,Ubuntu,RedHat,CentOS,Gentoo */
		if(options.volume != MAD_F_ONE)
			mpg321_alsa_set_volume((long)options.volume*volume_max/100);
#endif
	}
    }

    /* Fork here. */
    if(options.opt & MPG321_ENABLE_BUFFER)
    {
	    output_pid = fork();
	    if(output_pid == -1)
	    {
		    perror("Error while forking output process");
		    goto out; /* Release shared memeory and semaphores */
		//    exit(EXIT_FAILURE);
	    }

	    if(output_pid == 0)
	    {
		    frame_buffer_p();
		    exit(EXIT_SUCCESS);
	    }
	    signal(SIGUSR1,handle_signals);
	    if(!(options.opt & MPG321_REMOTE_PLAY))
	    {
#ifdef HAVE_ALSA
		    init_alsa_volume_control("default");
		    if(options.volume != MAD_F_ONE)
			    mpg321_alsa_set_volume((long)options.volume*volume_max/100);
#endif
	    }
    }

    if( (options.volume != MAD_F_ONE) && !(options.opt & MPG321_ENABLE_BUFFER))
    {
	    options.volume = mad_f_tofixed((long)options.volume/100.0);
    }
    else{
	    options.volume = MAD_F_ONE; /* When using the buffer options.volume when decoding each frame should be equal to MAD_F_ONE */
//	    options.volume = mad_f_tofixed((long)100.0/100.0);
    }

    if (!(options.opt & MPG321_REMOTE_PLAY))
    {
	     if(options.opt & MPG321_ENABLE_BASIC)
	     {
	 	     /* Now create and detach the basic controls thread */
		     sem_init(&main_lock,0,0);
	 	     pthread_create(&keyb_thread,NULL,read_keyb,NULL);
		     pthread_detach(keyb_thread);
	     }
     }
    if(set_xterm)
    {
	    tty_control();
	    get_term_title(title);
    }else
    {
     	
	    if (!(options.opt & MPG321_REMOTE_PLAY))
	    {
	    	    if (tcgetattr(0, &terminal_settings) < 0)
	    		    perror("tcgetattr()");
	    	    memcpy(&old_terminal_settings, &terminal_settings, sizeof(struct termios));
		    /* Early thread start */
		    sem_post(&main_lock);
	    }
    }
    /* Play the mpeg files or zip it! */
    while((currentfile = get_next_file(pl, &playbuf)))
    {
        //printf("Current File: %s\n",currentfile);
	   if (quit_now) 
            break;
        
        signal(SIGINT, SIG_DFL);
        
        playbuf.buf = NULL;
        playbuf.fd = -1;
        playbuf.length = 0;
        playbuf.done = 0;
        playbuf.num_frames = 0;
        current_frame = 0;
        playbuf.max_frames = -1;
        strncpy(playbuf.filename,currentfile, PATH_MAX);
        playbuf.filename[PATH_MAX-1] = '\0';
        
        if (status == MPG321_PLAYING || status == MPG321_STOPPED) 
            file_change = 1;

        mad_timer_reset(&playbuf.duration);
        
        mad_timer_reset(&current_time);

	id3struct = NULL;

        if (!(options.opt & MPG321_QUIET_PLAY) && file_change)
        {
           /* id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY);*/

            if (id3struct == NULL)
		    get_id3_info(currentfile, &id3struct, &id3tag);
	    if(id3tag)
		    show_id3(id3tag);
	}

	scrobbler_time = -1;
	if(options.opt & MPG321_USE_SCROBBLER)
	{
		if(id3struct == NULL)
			get_id3_info(currentfile,&id3struct,&id3tag);
                
	    if (id3tag)
	    {
		    char emptystring[31], emptyyear[5] = "    ";
		    int i;

		    if(parse_id3(scrobbler_args, id3tag))
		    {
			    memset(emptystring, ' ', 30);
			    emptystring[30] = '\0';
	    		    if((options.opt & MPG321_VERBOSE_PLAY) && (options.opt & MPG321_USE_SCROBBLER))
			    {
				    fprintf(stderr, "\nPreparing for the AudioScrobbler:\n");
				    for(i = 0; i < 6; i++)
				    {
					    if(scrobbler_args[i] == NULL)
						    scrobbler_args[i] =
							    ( i == 3 ? emptyyear: emptystring);
					    fprintf(stderr, "- %s\n", scrobbler_args[i]);
				    }
			    }
		    }
	    }
	}
      

        if (options.opt & MPG321_REMOTE_PLAY && file_change)
        {
		if(id3struct == NULL)
			get_id3_info(currentfile, &id3struct, &id3tag);
		if(id3tag)
                {
                    if (!show_id3(id3tag))
                    {
                        /* This shouldn't be necessary, but it appears that
                           libid3tag doesn't necessarily know if there are no
                           id3 tags on a given mp3 */
                        char * basec = strdup(currentfile);
                        char * basen = basename(basec);
                        
                        char * dot = strrchr(basen, '.');
                        
                        if (dot)
                            *dot = '\0';
                        
                        printf("@I %s\n", basen);

                        free(basec);
                    }
                }
            else
            {
                char * basec = strdup(currentfile);
                char * basen = basename(basec);
                
                char * dot = strrchr(basen, '.');
                
                if (dot)
                    *dot = '\0';
                
                printf("@I %s\n", basen);

                free(basec);
            }
        }

	if(id3struct != NULL)
		id3_file_close(id3struct);

        /* Create the MPEG stream */
        /* Check if source is on the network */
        if((fd = raw_open(currentfile)) != 0 || (fd = http_open(currentfile)) != 0
            || (fd = ftp_open(currentfile)) != 0)
        {
            playbuf.fd = fd;
            playbuf.buf = malloc(BUF_SIZE);
            playbuf.length = BUF_SIZE;
	    if(options.opt & MPG321_ENABLE_BUFFER)
	    {
		    Decoded_Frames->is_http = 1;
		    Decoded_Frames->is_file = 0;
	    }
	    calc_http_length(&playbuf);

            mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0,
                            output, handle_error, /* message */ 0);
        }

        /* Check if we are to use stdin for input */
        else if(strcmp(currentfile, "-") == 0)
        {
            playbuf.fd = fileno(stdin);
            playbuf.buf = malloc(BUF_SIZE);
            playbuf.length = BUF_SIZE;

            mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0,
                            output, handle_error, /* message */ 0);
        }
            
        /* currentfile is a local file (presumably.) mmap() it */
        else
        {
            struct stat stat;
            
            if((fd = open(currentfile, O_RDONLY)) == -1)
            {
	    
                mpg321_error(currentfile);
		/* Restore TTY from keyboard reader thread */
	        if(options.opt & MPG321_ENABLE_BASIC)
			if (tcsetattr(0, TCSANOW, &old_terminal_settings) < 0)
				perror("tcsetattr ICANON");
		if(set_xterm)
	    	{
			set_tty_restore();
	    		osc_print(0,0,title);
	    		if (ctty)
	    			fclose(ctty);
	    	}
		if( options.opt & MPG321_REMOTE_PLAY)
			if(remote_restart)
			{	
				clear_remote_file(pl); /* If restart is enabled, restart remote shell when file doesn't exist*/
				continue;
			}
		if(options.opt & MPG321_ENABLE_BUFFER)
			goto out;
		else
			exit(1);
                /* mpg123 stops immediately if it can't open a file */
		/* If sth goes wrong break!!!*/
                break;
            }

	    if(options.opt & MPG321_ENABLE_BUFFER)
	    {
		    Decoded_Frames->is_http = 0;
		    Decoded_Frames->is_file = 1;
	    }
            
            if(fstat(fd, &stat) == -1)
            {
                mpg321_error(currentfile);
		close(fd);
                continue;
            }
            
            if (!S_ISREG(stat.st_mode))
            {
		    if(S_ISFIFO(stat.st_mode))
		    {
			    fallback = 1;
			    goto fall_back_to_read_from_fd;
		    }

		close(fd);    
                continue;
            }
            
            retval = calc_length(currentfile, &playbuf); //FIXME Check also if it is an mp3 file. If not break and go to the next file possible
	    if(retval < 0)
	    {
		    if(options.opt & MPG321_REMOTE_PLAY)
		    {
			    fprintf(stderr,"@E Corrupted file: %s\n",currentfile);
			    close(fd);
			    if(remote_restart)
			    {
				    clear_remote_file(pl); /* If restart is enabled, restart remote shell when file is corrupted */
				    continue;
			    }
			    break;
		    }
		    mpg321_error(currentfile);
		    close(fd);
//		    break; //FIXME Break and stop OR continue the playlist ????
		    continue;
	    }

	    if((options.opt & MPG321_VERBOSE_PLAY) && (options.opt & MPG321_USE_SCROBBLER))
		    fprintf(stderr, "Track duration: %ld seconds\n",playbuf.duration.seconds);

	    if(options.opt & MPG321_USE_SCROBBLER)
		    scrobbler_set_time(playbuf.duration.seconds);

            if ((options.maxframes != -1) && (options.maxframes <= playbuf.num_frames))
            { 
                playbuf.max_frames = options.maxframes;
            }
            
            playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*));
            playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t));
#ifdef __uClinux__
	    if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
#else       
 	    if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
#endif		    
            {
                mpg321_error(currentfile);
                continue;
            }
            
            playbuf.frames[0] = playbuf.buf;
		    
	    mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0,
            
	    		    output, handle_error, /* message */ 0);
fall_back_to_read_from_fd:	//FIXME. Reported that on some embedded systems with low memory, less than 16MB doesn't work properly.
	    if(fallback)
	    {
	    
		    playbuf.fd = fd;
		    playbuf.buf = malloc(BUF_SIZE);
		    playbuf.length = BUF_SIZE;
		    mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0,
				    output, handle_error, /* message */ 0);
		    fallback = 1;
	    }
        }

        if(!(options.opt & MPG321_QUIET_PLAY))/*zip it!!!*/
        {
            /* Because dirname might modify the argument */
            char * dirc = strdup(currentfile);
            char * basec = strdup(currentfile);

            char * basen = basename(basec);
            char * dirn = dirname(dirc);
            
            /* make sure that the file has a pathname; otherwise don't print out
               a Directory: listing */
            if(strchr(currentfile, '/') && strncmp(old_dir, dirn, PATH_MAX) != 0)
            {
                /* Print information about the file */
                fprintf(stderr, "\n");
                fprintf(stderr,"Directory: %s\n", dirn);
                
                strncpy(old_dir, dirn, PATH_MAX);
                old_dir[PATH_MAX-1] = '\0';
            }
            
            /* print a newline between different songs only, not after
               Directory: listing */
            else
            {
                fprintf(stderr, "\n");
            }

            fprintf(stderr,"Playing MPEG stream from %s ...\n", basen);
            
	    /* Printing xterm title */
	    if(set_xterm)
	    {
		    osc_print(0,0,basen);
	    }
	    
            free(dirc);
            free(basec);
        }    

        signal(SIGINT, handle_signals);
	signal(SIGCHLD, handle_sigchld);
        /*Give control back so that we can implement SIG's*/
	if(set_xterm)
	{
		set_tty_restore();
		if (tcgetattr(0, &terminal_settings) < 0)
			perror("tcgetattr()");
		memcpy(&old_terminal_settings, &terminal_settings, sizeof(struct termios));
		/* disable canonical mode processing in the line discipline driver */
		terminal_settings.c_lflag &= ~(ICANON | ECHO);
		/* apply our new settings */
		if (tcsetattr(0, TCSANOW, &terminal_settings) < 0)
			perror("tcsetattr ICANON");
		if(options.opt & MPG321_ENABLE_BASIC)
		{
			/* Late thread start */
			sem_post(&main_lock);
		}
	}
        /* Every time the user gets us to rewind, we exit decoding,
           reinitialize it, and re-start it */
	    
	if(options.opt & MPG321_ENABLE_BUFFER)
    	{
		Decoded_Frames->total_decoded_frames = 0;
		Decoded_Frames->done = 0;
	}
      
        while (1)
        {
            decoder.options |= MAD_OPTION_IGNORECRC;
            mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
	    if(options.opt & MPG321_ENABLE_BUFFER)
	    {
		    static struct sembuf start_sops = {2,-1,0};
		    semop(semarray,&start_sops,1);
		    mad_decoder_position = 0;
		    output_buffer_position = 0;
		    union semun sem_ops;
		    sem_ops.val = 0;
		    semctl(semarray,2,SETVAL,sem_ops);
		    Decoded_Frames->total_decoded_frames = 0;
		    Decoded_Frames->done = 0;
		    Decoded_Frames->is_http = 0;
		    Decoded_Frames->is_file = 0;
	    }
            /* if we're rewinding on an mmap()ed stream */
            if(status == MPG321_REWINDING && playbuf.fd == -1) 
            {
                mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0,
                    output, /*error*/0, /* message */ 0);
            }    
            else
                break;
        } 

        if (!(options.opt & MPG321_QUIET_PLAY))
        {
            char time_formatted[11];
            mad_timer_string(current_time, time_formatted, "%.1u:%.2u", MAD_UNITS_MINUTES,
                       MAD_UNITS_SECONDS, 0);
	    fprintf(stderr,"                                                                            \r");
	    fprintf(stderr, "\n[%s] Decoding of %s finished.\n",time_formatted, basename(currentfile)); /* Report total decoded seconds. Maybe for the frame buffer report only total played time?? */
        }
        
        if (options.opt & MPG321_REMOTE_PLAY && status == MPG321_STOPPED)
        {
            clear_remote_file(pl);
        }

        mad_decoder_finish(&decoder);

        if (playbuf.frames)
             free(playbuf.frames);

        if (playbuf.times)
            free(playbuf.times);
            
        if (playbuf.fd == -1)
        {
            munmap(playbuf.buf, playbuf.length);
            close(fd);
        }

        else
        {
            free(playbuf.buf);
            if (playbuf.fd != fileno(stdin)) 
                close(playbuf.fd);
        }
    }

    if(!(options.opt & MPG321_ENABLE_BUFFER))
    {
  	     if(playdevice)
		     ao_close(playdevice);
	     ao_shutdown();
     }

     if (!(options.opt & MPG321_REMOTE_PLAY))
     {
	     if(options.opt & MPG321_ENABLE_BASIC)
	     {
	 	     pflag = 1;
		     /* Restore TTY from keyboard reader thread */
	 	     if (tcsetattr(0, TCSANOW, &old_terminal_settings) < 0)
		 	     perror("tcsetattr ICANON");
	     }
     }
    /*Restoring TTY*/
    if(set_xterm)
    {
	    set_tty_restore();
	    osc_print(0,0,title);
	    if (ctty)
		    fclose(ctty);
    }

out:
    if(options.opt & MPG321_ENABLE_BUFFER)
    {
	    if(kill(output_pid,SIGUSR1) == -1)
		    perror("Error while stopping output process");
	    static int wstatus;
	    wait(&wstatus);
	    if(wstatus == -1)
		    perror("Error while waiting for output process to exit");
	    if(semctl(semarray,0,IPC_RMID) == -1)
		    perror("Error while destroying semaphores");
	    if(shmdt(Output_Queue) == -1)
		    perror("Error while detaching shared buffer");
	    if(shmctl(shm_id,IPC_RMID,NULL))
		    perror("Cannot destroy shared buffer");
	    if(shmctl(frames_id,IPC_RMID,NULL))
		    perror("Cannot destroy shared buffer");
    }
    return(0);
}
bool Mp3AudioFileReader::run(AudioProcessor& processor)
{
    if (file_ == nullptr) {
        return false;
    }

    enum {
        STATUS_OK,
        STATUS_INIT_ERROR,
        STATUS_READ_ERROR,
        STATUS_PROCESS_ERROR
    } status = STATUS_OK;

    unsigned char input_buffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
    unsigned char* guard_ptr = nullptr;
    unsigned long frame_count = 0;

    short output_buffer[OUTPUT_BUFFER_SIZE];
    short* output_ptr = output_buffer;
    const short* const output_buffer_end = output_buffer + OUTPUT_BUFFER_SIZE;

    int channels = 0;

    // Decoding options can here be set in the options field of the stream
    // structure.

    // {1} When decoding from a file we need to know when the end of the file is
    // reached at the same time as the last bytes are read (see also the comment
    // marked {3} below). Neither the standard C fread() function nor the POSIX
    // read() system call provides this feature. We thus need to perform our
    // reads through an interface having this feature, this is implemented here
    // by the bstdfile.c module.

    BStdFile bstd_file(file_);

    // Initialize the structures used by libmad.
    MadStream stream;
    MadFrame frame;
    MadSynth synth;

    mad_timer_t timer;
    mad_timer_reset(&timer);

    // This is the decoding loop.

    for (;;) {
        // The input bucket must be filled if it becomes empty or if it's the
        // first execution of the loop.

        if (stream.buffer == nullptr || stream.error == MAD_ERROR_BUFLEN) {
            size_t read_size;
            size_t remaining;
            unsigned char* read_start;

            // {2} libmad may not consume all bytes of the input buffer. If the
            // last frame in the buffer is not wholly contained by it, then that
            // frame's start is pointed by the next_frame member of the stream
            // structure. This common situation occurs when mad_frame_decode()
            // fails, sets the stream error code to MAD_ERROR_BUFLEN, and sets
            // the next_frame pointer to a non-NULL value. (See also the comment
            // marked {4} below.)
            //
            // When this occurs, the remaining unused bytes must be put back at
            // the beginning of the buffer and taken in account before refilling
            // the buffer. This means that the input buffer must be large enough
            // to hold a whole frame at the highest observable bit-rate
            // (currently 448 kb/s). XXX=XXX Is 2016 bytes the size of the
            // largest frame? (448000*(1152/32000))/8

            if (stream.next_frame != nullptr) {
                remaining = stream.bufend - stream.next_frame;
                memmove(input_buffer, stream.next_frame, remaining);
                read_start = input_buffer + remaining;
                read_size  = INPUT_BUFFER_SIZE - remaining;
            }
            else {
                read_size  = INPUT_BUFFER_SIZE;
                read_start = input_buffer;
                remaining = 0;
            }

            // Fill-in the buffer. If an error occurs print a message and leave
            // the decoding loop. If the end of stream is reached we also leave
            // the loop but the return status is left untouched.

            read_size = bstd_file.read(read_start, 1, read_size);

            if (read_size <= 0) {
                if (ferror(file_)) {
                    error_stream << "\nRead error on bit-stream: "
                                 << strerror(errno) << '\n';
                    status = STATUS_READ_ERROR;
                }

                break;
            }

            // {3} When decoding the last frame of a file, it must be followed
            // by MAD_BUFFER_GUARD zero bytes if one wants to decode that last
            // frame. When the end of file is detected we append that quantity
            // of bytes at the end of the available data. Note that the buffer
            // can't overflow as the guard size was allocated but not used the
            // the buffer management code. (See also the comment marked {1}.)
            //
            // In a message to the mad-dev mailing list on May 29th, 2001, Rob
            // Leslie explains the guard zone as follows:
            //
            //    "The reason for MAD_BUFFER_GUARD has to do with the way
            //    decoding is performed. In Layer III, Huffman decoding may
            //    inadvertently read a few bytes beyond the end of the buffer in
            //    the case of certain invalid input. This is not detected until
            //    after the fact. To prevent this from causing problems, and
            //    also to ensure the next frame's main_data_begin pointer is
            //    always accessible, MAD requires MAD_BUFFER_GUARD (currently 8)
            //    bytes to be present in the buffer past the end of the current
            //    frame in order to decode the frame."

            if (bstd_file.eof()) {
                guard_ptr = read_start + read_size;
                memset(guard_ptr, 0, MAD_BUFFER_GUARD);
                read_size += MAD_BUFFER_GUARD;
            }

            // Pipe the new buffer content to libmad's stream decoder facility.
            mad_stream_buffer(&stream, input_buffer, read_size + remaining);
            stream.error = MAD_ERROR_NONE;
        }

        // Decode the next MPEG frame. The streams is read from the buffer, its
        // constituents are break down and stored the the frame structure, ready
        // for examination/alteration or PCM synthesis. Decoding options are
        // carried in the frame structure from the stream structure.
        //
        // Error handling: mad_frame_decode() returns a non zero value when an
        // error occurs. The error condition can be checked in the error member
        // of the stream structure. A mad error is recoverable or fatal, the
        // error status is checked with the MAD_RECOVERABLE macro.
        //
        // {4} When a fatal error is encountered all decoding activities shall
        // be stopped, except when a MAD_ERROR_BUFLEN is signaled. This
        // condition means that the mad_frame_decode() function needs more input
        // to complete its work. One shall refill the buffer and repeat the
        // mad_frame_decode() call. Some bytes may be left unused at the end of
        // the buffer if those bytes forms an incomplete frame. Before
        // refilling, the remaining bytes must be moved to the beginning of the
        // buffer and used for input for the next mad_frame_decode() invocation.
        // (See the comments marked {2} earlier for more details.)
        //
        // Recoverable errors are caused by malformed bit-streams, in this case
        // one can call again mad_frame_decode() in order to skip the faulty
        // part and re-sync to the next frame.

        if (mad_frame_decode(&frame, &stream)) {
            if (MAD_RECOVERABLE(stream.error)) {
                // Do not print a message if the error is a loss of
                // synchronization and this loss is due to the end of stream
                // guard bytes. (See the comment marked {3} above for more
                // information about guard bytes.)

                if (stream.error != MAD_ERROR_LOSTSYNC ||
                    stream.this_frame != guard_ptr) {

                    // For any MP3 file we typically see two errors in the
                    // first frame processed:
                    // - lost synchronization
                    // - reserved header layer value
                    // This seems to be OK, so don't print these

                    if (frame_count != 0) {
                        error_stream << "\nRecoverable frame level error: "
                                     << mad_stream_errorstr(&stream) << '\n';
                    }
                }

                continue;
            }
            else {
                if (stream.error == MAD_ERROR_BUFLEN) {
                    continue;
                }
                else {
                    error_stream << "\nUnrecoverable frame level error: "
                                 << mad_stream_errorstr(&stream) << '\n';
                    status = STATUS_READ_ERROR;
                    break;
                }
            }
        }

        // Display the characteristics of the stream's first frame. The first
        // frame is representative of the entire stream.

        if (frame_count == 0) {
            const int sample_rate = frame.header.samplerate;
            channels = MAD_NCHANNELS(&frame.header);

            dumpInfo(output_stream, frame.header);

            if (!processor.init(sample_rate, channels, OUTPUT_BUFFER_SIZE)) {
                status = STATUS_PROCESS_ERROR;
                break;
            }

            showProgress(0, file_size_);
        }

        // Accounting. The computed frame duration is in the frame header
        // structure. It is expressed as a fixed point number whole data type is
        // mad_timer_t. It is different from the samples fixed point format and
        // unlike it, it can't directly be added or subtracted. The timer module
        // provides several functions to operate on such numbers. Be careful
        // there, as some functions of libmad's timer module receive some of
        // their mad_timer_t arguments by value!

        frame_count++;
        mad_timer_add(&timer, frame.header.duration);

        // Once decoded the frame is synthesized to PCM samples. No errors are
        // reported by mad_synth_frame();

        mad_synth_frame(&synth, &frame);

        // Synthesized samples must be converted from libmad's fixed point
        // number to the consumer format. Here we use signed 16 bit integers on
        // two channels. Integer samples are temporarily stored in a buffer that
        // is flushed when full.

        for (int i = 0; i < synth.pcm.length; i++) {
            // Left channel
            short sample = MadFixedToSshort(synth.pcm.samples[0][i]);

            *output_ptr++ = sample;

            // Right channel. If the decoded stream is monophonic then the right
            // output channel is the same as the left one.

            if (MAD_NCHANNELS(&frame.header) == 2) {
                sample = MadFixedToSshort(synth.pcm.samples[1][i]);
                *output_ptr++ = sample;
            }

            // Flush the output buffer if it is full

            if (output_ptr == output_buffer_end) {
                long pos = ftell(file_);

                showProgress(pos, file_size_);

                bool success = processor.process(
                    output_buffer,
                    OUTPUT_BUFFER_SIZE / channels
                );

                if (!success) {
                    status = STATUS_PROCESS_ERROR;
                    break;
                }

                output_ptr = output_buffer;
            }
        }
    }

    // If the output buffer is not empty and no error occurred during the last
    // write, then flush it.

    if (output_ptr != output_buffer && status != STATUS_PROCESS_ERROR) {
        int buffer_size = static_cast<int>(output_ptr - output_buffer);

        bool success = processor.process(output_buffer, buffer_size / channels);

        if (!success) {
            status = STATUS_PROCESS_ERROR;
        }
    }

    // Accounting report if no error occurred.

    if (status == STATUS_OK) {
        // Report 100% done.
        showProgress(file_size_, file_size_);

        char buffer[80];

        // The duration timer is converted to a human readable string with the
        // versatile, but still constrained mad_timer_string() function, in a
        // fashion not unlike strftime(). The main difference is that the timer
        // is broken into several values according some of its arguments. The
        // units and fracunits arguments specify the intended conversion to be
        // executed.
        //
        // The conversion unit (MAD_UNIT_MINUTES in our example) also specify
        // the order and kind of conversion specifications that can be used in
        // the format string.
        //
        // It is best to examine libmad's timer.c source-code for details of the
        // available units, fraction of units, their meanings, the format
        // arguments, etc.

        mad_timer_string(timer, buffer, "%lu:%02lu.%03u",
            MAD_UNITS_MINUTES, MAD_UNITS_MILLISECONDS, 0);

        output_stream << "\nFrames decoded: " << frame_count
                      << " (" << buffer << ")\n";
    }

    processor.done();

    close();

    return status == STATUS_OK;
}
Exemplo n.º 7
0
/****************************************************************************
 * Main decoding loop. This is where mad is used.							*
 ****************************************************************************/
#define INPUT_BUFFER_SIZE	(5*8192)
#define OUTPUT_BUFFER_SIZE	8192 /* Must be an integer multiple of 4. */
static int MpegAudioDecoder(FILE *InputFp, FILE *OutputFp)
{
	struct mad_stream	Stream;
	struct mad_frame	Frame;
	struct mad_synth	Synth;
	mad_timer_t			Timer;
	unsigned char		InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD],
						OutputBuffer[OUTPUT_BUFFER_SIZE],
						*OutputPtr=OutputBuffer,
						*GuardPtr=NULL;
	const unsigned char	*OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
	int					Status=0,
						i;
	unsigned long		FrameCount=0;
	bstdfile_t			*BstdFile;

	/* First the structures used by libmad must be initialized. */
	mad_stream_init(&Stream);
	mad_frame_init(&Frame);
	mad_synth_init(&Synth);
	mad_timer_reset(&Timer);

	/* Decoding options can here be set in the options field of the
	 * Stream structure.
	 */

	/* {1} When decoding from a file we need to know when the end of
	 * the file is reached at the same time as the last bytes are read
	 * (see also the comment marked {3} bellow). Neither the standard
	 * C fread() function nor the POSIX read() system call provides
	 * this feature. We thus need to perform our reads through an
	 * interface having this feature, this is implemented here by the
	 * bstdfile.c module.
	 */
	BstdFile=NewBstdFile(InputFp);
	if(BstdFile==NULL)
	{
		fprintf(stderr,"%s: can't create a new bstdfile_t (%s).\n",
				ProgName,strerror(errno));
		return(1);
	}

	/* This is the decoding loop. */
	do
	{
		/* The input bucket must be filled if it becomes empty or if
		 * it's the first execution of the loop.
		 */
		if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
		{
			size_t			ReadSize,
							Remaining;
			unsigned char	*ReadStart;

			/* {2} libmad may not consume all bytes of the input
			 * buffer. If the last frame in the buffer is not wholly
			 * contained by it, then that frame's start is pointed by
			 * the next_frame member of the Stream structure. This
			 * common situation occurs when mad_frame_decode() fails,
			 * sets the stream error code to MAD_ERROR_BUFLEN, and
			 * sets the next_frame pointer to a non NULL value. (See
			 * also the comment marked {4} bellow.)
			 *
			 * When this occurs, the remaining unused bytes must be
			 * put back at the beginning of the buffer and taken in
			 * account before refilling the buffer. This means that
			 * the input buffer must be large enough to hold a whole
			 * frame at the highest observable bit-rate (currently 448
			 * kb/s). XXX=XXX Is 2016 bytes the size of the largest
			 * frame? (448000*(1152/32000))/8
			 */
			if(Stream.next_frame!=NULL)
			{
				Remaining=Stream.bufend-Stream.next_frame;
				memmove(InputBuffer,Stream.next_frame,Remaining);
				ReadStart=InputBuffer+Remaining;
				ReadSize=INPUT_BUFFER_SIZE-Remaining;
			}
			else
				ReadSize=INPUT_BUFFER_SIZE,
					ReadStart=InputBuffer,
					Remaining=0;

			/* Fill-in the buffer. If an error occurs print a message
			 * and leave the decoding loop. If the end of stream is
			 * reached we also leave the loop but the return status is
			 * left untouched.
			 */
			ReadSize=BstdRead(ReadStart,1,ReadSize,BstdFile);
			if(ReadSize<=0)
			{
				if(ferror(InputFp))
				{
					fprintf(stderr,"%s: read error on bit-stream (%s)\n",
							ProgName,strerror(errno));
					Status=1;
				}
				if(feof(InputFp))
					fprintf(stderr,"%s: end of input stream\n",ProgName);
				break;
			}

			/* {3} When decoding the last frame of a file, it must be
			 * followed by MAD_BUFFER_GUARD zero bytes if one wants to
			 * decode that last frame. When the end of file is
			 * detected we append that quantity of bytes at the end of
			 * the available data. Note that the buffer can't overflow
			 * as the guard size was allocated but not used the the
			 * buffer management code. (See also the comment marked
			 * {1}.)
			 *
			 * In a message to the mad-dev mailing list on May 29th,
			 * 2001, Rob Leslie explains the guard zone as follows:
			 *
			 *    "The reason for MAD_BUFFER_GUARD has to do with the
			 *    way decoding is performed. In Layer III, Huffman
			 *    decoding may inadvertently read a few bytes beyond
			 *    the end of the buffer in the case of certain invalid
			 *    input. This is not detected until after the fact. To
			 *    prevent this from causing problems, and also to
			 *    ensure the next frame's main_data_begin pointer is
			 *    always accessible, MAD requires MAD_BUFFER_GUARD
			 *    (currently 8) bytes to be present in the buffer past
			 *    the end of the current frame in order to decode the
			 *    frame."
			 */
			if(BstdFileEofP(BstdFile))
			{
				GuardPtr=ReadStart+ReadSize;
				memset(GuardPtr,0,MAD_BUFFER_GUARD);
				ReadSize+=MAD_BUFFER_GUARD;
			}

			/* Pipe the new buffer content to libmad's stream decoder
             * facility.
			 */
			mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
			Stream.error=0;
		}

		/* Decode the next MPEG frame. The streams is read from the
		 * buffer, its constituents are break down and stored the the
		 * Frame structure, ready for examination/alteration or PCM
		 * synthesis. Decoding options are carried in the Frame
		 * structure from the Stream structure.
		 *
		 * Error handling: mad_frame_decode() returns a non zero value
		 * when an error occurs. The error condition can be checked in
		 * the error member of the Stream structure. A mad error is
		 * recoverable or fatal, the error status is checked with the
		 * MAD_RECOVERABLE macro.
		 *
		 * {4} When a fatal error is encountered all decoding
		 * activities shall be stopped, except when a MAD_ERROR_BUFLEN
		 * is signaled. This condition means that the
		 * mad_frame_decode() function needs more input to complete
		 * its work. One shall refill the buffer and repeat the
		 * mad_frame_decode() call. Some bytes may be left unused at
		 * the end of the buffer if those bytes forms an incomplete
		 * frame. Before refilling, the remaining bytes must be moved
		 * to the beginning of the buffer and used for input for the
		 * next mad_frame_decode() invocation. (See the comments
		 * marked {2} earlier for more details.)
		 *
		 * Recoverable errors are caused by malformed bit-streams, in
		 * this case one can call again mad_frame_decode() in order to
		 * skip the faulty part and re-sync to the next frame.
		 */
		if(mad_frame_decode(&Frame,&Stream))
		{
			if(MAD_RECOVERABLE(Stream.error))
			{
				/* Do not print a message if the error is a loss of
				 * synchronization and this loss is due to the end of
				 * stream guard bytes. (See the comments marked {3}
				 * supra for more informations about guard bytes.)
				 */
				if(Stream.error!=MAD_ERROR_LOSTSYNC ||
				   Stream.this_frame!=GuardPtr)
				{
					fprintf(stderr,"%s: recoverable frame level error (%s)\n",
							ProgName,MadErrorString(&Stream));
					fflush(stderr);
				}
				continue;
			}
			else
				if(Stream.error==MAD_ERROR_BUFLEN)
					continue;
				else
				{
					fprintf(stderr,"%s: unrecoverable frame level error (%s).\n",
							ProgName,MadErrorString(&Stream));
					Status=1;
					break;
				}
		}

		/* The characteristics of the stream's first frame is printed
		 * on stderr. The first frame is representative of the entire
		 * stream.
		 */
		if(FrameCount==0)
			if(PrintFrameInfo(stderr,&Frame.header))
			{
				Status=1;
				break;
			}

		/* Accounting. The computed frame duration is in the frame
		 * header structure. It is expressed as a fixed point number
		 * whole data type is mad_timer_t. It is different from the
		 * samples fixed point format and unlike it, it can't directly
		 * be added or subtracted. The timer module provides several
		 * functions to operate on such numbers. Be careful there, as
		 * some functions of libmad's timer module receive some of
		 * their mad_timer_t arguments by value!
		 */
		FrameCount++;
		mad_timer_add(&Timer,Frame.header.duration);

		/* Between the frame decoding and samples synthesis we can
		 * perform some operations on the audio data. We do this only
		 * if some processing was required. Detailed explanations are
		 * given in the ApplyFilter() function.
		 */
		if(DoFilter)
			ApplyFilter(&Frame);

		/* Once decoded the frame is synthesized to PCM samples. No errors
		 * are reported by mad_synth_frame();
		 */
		mad_synth_frame(&Synth,&Frame);

		/* Synthesized samples must be converted from libmad's fixed
		 * point number to the consumer format. Here we use unsigned
		 * 16 bit big endian integers on two channels. Integer samples
		 * are temporarily stored in a buffer that is flushed when
		 * full.
		 */
		for(i=0;i<Synth.pcm.length;i++)
		{
			signed short	Sample;

			/* Left channel */
			Sample=MadFixedToSshort(Synth.pcm.samples[0][i]);
			*(OutputPtr++)=Sample>>8;
			*(OutputPtr++)=Sample&0xff;

			/* Right channel. If the decoded stream is monophonic then
			 * the right output channel is the same as the left one.
			 */
			if(MAD_NCHANNELS(&Frame.header)==2)
				Sample=MadFixedToSshort(Synth.pcm.samples[1][i]);
			*(OutputPtr++)=Sample>>8;
			*(OutputPtr++)=Sample&0xff;

			/* Flush the output buffer if it is full. */
			if(OutputPtr==OutputBufferEnd)
			{
				if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,OutputFp)!=OUTPUT_BUFFER_SIZE)
				{
					fprintf(stderr,"%s: PCM write error (%s).\n",
							ProgName,strerror(errno));
					Status=2;
					break;
				}
				OutputPtr=OutputBuffer;
			}
		}
	}while(1);

	/* The input file was completely read; the memory allocated by our
	 * reading module must be reclaimed.
	 */
	BstdFileDestroy(BstdFile);

	/* Mad is no longer used, the structures that were initialized must
     * now be cleared.
	 */
	mad_synth_finish(&Synth);
	mad_frame_finish(&Frame);
	mad_stream_finish(&Stream);

	/* If the output buffer is not empty and no error occurred during
     * the last write, then flush it.
	 */
	if(OutputPtr!=OutputBuffer && Status!=2)
	{
		size_t	BufferSize=OutputPtr-OutputBuffer;

		if(fwrite(OutputBuffer,1,BufferSize,OutputFp)!=BufferSize)
		{
			fprintf(stderr,"%s: PCM write error (%s).\n",
					ProgName,strerror(errno));
			Status=2;
		}
	}

	/* Accounting report if no error occurred. */
	if(!Status)
	{
		char	Buffer[80];

		/* The duration timer is converted to a human readable string
		 * with the versatile, but still constrained mad_timer_string()
		 * function, in a fashion not unlike strftime(). The main
		 * difference is that the timer is broken into several
		 * values according some of it's arguments. The units and
		 * fracunits arguments specify the intended conversion to be
		 * executed.
		 *
		 * The conversion unit (MAD_UNIT_MINUTES in our example) also
		 * specify the order and kind of conversion specifications
		 * that can be used in the format string.
		 *
		 * It is best to examine libmad's timer.c source-code for details
		 * of the available units, fraction of units, their meanings,
		 * the format arguments, etc.
		 */
		mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u",
						 MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0);
		fprintf(stderr,"%s: %lu frames decoded (%s).\n",
				ProgName,FrameCount,Buffer);
	}

	/* That's the end of the world (in the H. G. Wells way). */
	return(Status);
}
Exemplo n.º 8
0
  /* scale */
  return output >> scalebits;
}

#define INPUT_BUFFER_SIZE  (5*8192)
#define OUTPUT_BUFFER_SIZE  8192 /* Must be an integer multiple of 4. */
void real_mpeg_play(char* fname)
{
    unsigned char InputBuffer[INPUT_BUFFER_SIZE],
        OutputBuffer[OUTPUT_BUFFER_SIZE],
        *OutputPtr=OutputBuffer;
    const unsigned char  *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
    int Status=0, i, fd;
    unsigned long FrameCount=0;
    sound_t sound;
    struct mp3entry mp3;
    static struct dither d0, d1;
    int key=0;
  
    mp3info(&mp3, fname, false); /* FIXME: honor the v1first setting */

    init_sound(&sound);

    /* Configure sound device for this file - always select Stereo because
       some sound cards don't support mono */
    config_sound(&sound,mp3.frequency,2);

    if ((fd=open(fname,O_RDONLY)) < 0) {
        fprintf(stderr,"could not open %s\n",fname);
        return;
    }

    /* First the structures used by libmad must be initialized. */
    mad_stream_init(&Stream);
    mad_frame_init(&Frame);
    mad_synth_init(&Synth);
    mad_timer_reset(&Timer);

    do {
        if (Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) {
            size_t ReadSize,Remaining;
            unsigned char *ReadStart;

            if(Stream.next_frame!=NULL) {
                Remaining=Stream.bufend-Stream.next_frame;
                memmove(InputBuffer,Stream.next_frame,Remaining);
                ReadStart=InputBuffer+Remaining;
                ReadSize=INPUT_BUFFER_SIZE-Remaining;
            } else {
                ReadSize=INPUT_BUFFER_SIZE,
                    ReadStart=InputBuffer,
                    Remaining=0;
            }

            if ((int)(ReadSize=read(fd,ReadStart,ReadSize)) < 0) {
                fprintf(stderr,"end of input stream\n");
                break;
            }

            mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
            Stream.error=0;
        }

        if(mad_frame_decode(&Frame,&Stream)) {
            if(MAD_RECOVERABLE(Stream.error)) {
                fprintf(stderr,"recoverable frame level error\n");
                fflush(stderr);
                continue;
            } else {
                if(Stream.error==MAD_ERROR_BUFLEN) {
                    continue;
                } else {
                    fprintf(stderr,"unrecoverable frame level error\n");
                    Status=1;
                    break;
                }
            }
        }

        FrameCount++;
        mad_timer_add(&Timer,Frame.header.duration);
        
        mad_synth_frame(&Synth,&Frame);

        for(i=0;i<Synth.pcm.length;i++) {
            unsigned short  Sample;
            
            /* Left channel */
            Sample=scale(Synth.pcm.samples[0][i],&d0);
            *(OutputPtr++)=Sample&0xff;
            *(OutputPtr++)=Sample>>8;
            
            /* Right channel. If the decoded stream is monophonic then
             * the right output channel is the same as the left one.
             */
            if(MAD_NCHANNELS(&Frame.header)==2) {
                Sample=scale(Synth.pcm.samples[1][i],&d1);
            }

            *(OutputPtr++)=Sample&0xff;
            *(OutputPtr++)=Sample>>8;
            
            /* Flush the buffer if it is full. */
            if (OutputPtr==OutputBufferEnd) {
                if (output_sound(&sound, OutputBuffer,
                                 OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE) {
                    fprintf(stderr,"PCM write error.\n");
                    Status=2;
                    break;
                }
                OutputPtr=OutputBuffer;
            }
            }

        if ((key=button_get(0))==BUTTON_STOP)
	{
            break; 
	}

    }while(1);
    
    /* Mad is no longer used, the structures that were initialized must
     * now be cleared.
     */
    mad_synth_finish(&Synth);
    mad_frame_finish(&Frame);
    mad_stream_finish(&Stream);

    /* If the output buffer is not empty and no error occured during
     * the last write, then flush it. */
    if(OutputPtr!=OutputBuffer && Status!=2)
        {
            size_t  BufferSize=OutputPtr-OutputBuffer;

            if (output_sound(&sound, OutputPtr, BufferSize)!=(int)BufferSize)
                {
                    fprintf(stderr,"PCM write error\n");
                    Status=2;
                }
        }

    /* Accounting report if no error occured. */
    if(!Status)
        {
            char  Buffer[80];

            mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u",
                             MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0);
            fprintf(stderr,"%lu frames decoded (%s).\n",FrameCount,Buffer);
        }

    close_sound(&sound);
    /* That's the end of the world (in the H. G. Wells way). */
    return;
}
Exemplo n.º 9
0
Arquivo: mpg321.c Projeto: e3c/mpg321
int main(int argc, char *argv[])
{
    int fd = 0;
    char *currentfile, old_dir[PATH_MAX];
    playlist *pl = NULL;
    struct id3_file *id3struct = NULL;
    struct id3_tag *id3tag = NULL;

    buffer playbuf;
    
    struct mad_decoder decoder;

    old_dir[0] = '\0';

    playbuf.pl = pl = new_playlist();

    if (!pl)
    {
        fprintf(stderr, "malloc failed at startup!\n");
        exit(1);
    }

    options.volume = MAD_F_ONE;

    status = MPG321_PLAYING;
    
    /* Get the command line options */
    parse_options(argc, argv, pl);

    /* If there were no files and no playlist specified just print the usage */
    if (!playlist_file && optind == argc)
    {
        usage(argv[0]);
        exit(0);
    }

    if (playlist_file)
        load_playlist(pl, playlist_file);
    
    add_cmdline_files(pl, argv);

    if (shuffle_play)
        shuffle_files(pl);

    ao_initialize();

    check_default_play_device();
    
    if (!(options.opt & MPG321_REMOTE_PLAY))
    {
        handle_signals(-1); /* initialize signal handler */
     
        remote_input_buf[0] = '\0';
    }
    
    if (!(options.opt & MPG321_QUIET_PLAY)) 
        mpg123_boilerplate();
    
    if (options.opt & MPG321_REMOTE_PLAY)
    {
        printf ("@R MPG123\n");
    }
    
    /* Play the mpeg files or zip it! */
    while((currentfile = get_next_file(pl, &playbuf)))
    {
        if (quit_now) 
            break;
        
        signal(SIGINT, SIG_DFL);
        
        playbuf.buf = NULL;
        playbuf.fd = -1;
        playbuf.length = 0;
        playbuf.done = 0;
        playbuf.num_frames = 0;
        playbuf.max_frames = -1;
        strncpy(playbuf.filename,currentfile, PATH_MAX);
        playbuf.filename[PATH_MAX-1] = '\0';
        
        if (status == MPG321_PLAYING) 
            file_change = 1;

        mad_timer_reset(&playbuf.duration);
        
        mad_timer_reset(&current_time);

        if (!(options.opt & MPG321_QUIET_PLAY) && file_change)
        {
            id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY);

            if (id3struct)
            {
                id3tag = id3_file_tag (id3struct);
            
                if (id3tag)
                {
                    show_id3 (id3tag);
                }

                id3_file_close (id3struct);
            }
        }

        if (options.opt & MPG321_REMOTE_PLAY && file_change)
        {
            id3struct = id3_file_open (currentfile, ID3_FILE_MODE_READONLY);

            if (id3struct)
            {
                id3tag = id3_file_tag (id3struct);
            
                if (id3tag)
                {
                    if (!show_id3(id3tag))
                    {
                        /* This shouldn't be necessary, but it appears that
                           libid3tag doesn't necessarily know if there are no
                           id3 tags on a given mp3 */
                        char * basec = strdup(currentfile);
                        char * basen = basename(basec);
                        
                        char * dot = strrchr(basen, '.');
                        
                        if (dot)
                            *dot = '\0';
                        
                        printf("@I %s\n", basen);

                        free(basec);
                    }
                }
                
                else
                {
                    fprintf(stderr, "Allocation error");
                    exit(1);
                }

                id3_file_close (id3struct);
            }
            
            else
            {
                char * basec = strdup(currentfile);
                char * basen = basename(basec);
                
                char * dot = strrchr(basen, '.');
                
                if (dot)
                    *dot = '\0';
                
                printf("@I %s\n", basen);

                free(basec);
            }
        }

        /* Create the MPEG stream */
        /* Check if source is on the network */
        if((fd = raw_open(currentfile)) != 0 || (fd = http_open(currentfile)) != 0
            || (fd = ftp_open(currentfile)) != 0)
        {
            playbuf.fd = fd;
            playbuf.buf = malloc(BUF_SIZE);
            playbuf.length = BUF_SIZE;
            
            mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0,
                            output, /*error*/0, /* message */ 0);
        }

        /* Check if we are to use stdin for input */
        else if(strcmp(currentfile, "-") == 0)
        {
            playbuf.fd = fileno(stdin);
            playbuf.buf = malloc(BUF_SIZE);
            playbuf.length = BUF_SIZE;

            mad_decoder_init(&decoder, &playbuf, read_from_fd, read_header, /*filter*/0,
                            output, /*error*/0, /* message */ 0);
        }
            
        /* currentfile is a local file (presumably.) mmap() it */
        else
        {
            struct stat stat;
            
            if((fd = open(currentfile, O_RDONLY)) == -1)
            {
                mpg321_error(currentfile);

                /* mpg123 stops immediately if it can't open a file */
                break;
            }
            
            if(fstat(fd, &stat) == -1)
            {
                close(fd);
                mpg321_error(currentfile);
                continue;
            }
            
            if (!S_ISREG(stat.st_mode))
            {
                close(fd);
                continue;
            }
            
            calc_length(currentfile, &playbuf);

            if ((options.maxframes != -1) && (options.maxframes <= playbuf.num_frames))
            { 
                playbuf.max_frames = options.maxframes;
            }
            
            playbuf.frames = malloc((playbuf.num_frames + 1) * sizeof(void*));
            playbuf.times = malloc((playbuf.num_frames + 1) * sizeof(mad_timer_t));
    
            if((playbuf.buf = mmap(0, playbuf.length, PROT_READ, MAP_SHARED, fd, 0))
                                == MAP_FAILED)
            {
                close(fd);
                mpg321_error(currentfile);
                continue;
            }
            
            close(fd);
            playbuf.frames[0] = playbuf.buf;
            
            mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0,
                            output, /*error*/0, /* message */ 0);
        }

        if(!(options.opt & MPG321_QUIET_PLAY))/*zip it!!!*/
        {
            /* Because dirname might modify the argument */
            char * dirc = strdup(currentfile);
            char * basec = strdup(currentfile);

            char * basen = basename(basec);
            char * dirn = dirname(dirc);
            
            /* make sure that the file has a pathname; otherwise don't print out
               a Directory: listing */
            if(strchr(currentfile, '/') && strncmp(old_dir, dirn, PATH_MAX) != 0)
            {
                /* Print information about the file */
                fprintf(stderr, "\n");
                fprintf(stderr,"Directory: %s/\n", dirn);
                
                strncpy(old_dir, dirn, PATH_MAX);
                old_dir[PATH_MAX-1] = '\0';
            }
            
            /* print a newline between different songs only, not after
               Directory: listing */
            else
            {
                fprintf(stderr, "\n");
            }

            fprintf(stderr,"Playing MPEG stream from %s ...\n", basen);
    
            free(dirc);
            free(basec);
        }    

        signal(SIGINT, handle_signals);

        /* Every time the user gets us to rewind, we exit decoding,
           reinitialize it, and re-start it */
        while (1)
        {
            mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
            
            /* if we're rewinding on an mmap()ed stream */
            if(status == MPG321_REWINDING && playbuf.fd == -1) 
            {
                mad_decoder_init(&decoder, &playbuf, read_from_mmap, read_header, /*filter*/0,
                    output, /*error*/0, /* message */ 0);
            }    
            else
                break;
        } 

        if (!(options.opt & MPG321_QUIET_PLAY))
        {
            char time_formatted[11];
            mad_timer_string(current_time, time_formatted, "%.1u:%.2u", MAD_UNITS_MINUTES,
                       MAD_UNITS_SECONDS, 0);
            fprintf(stderr, "\n[%s] Decoding of %s finished.\n",time_formatted, basename(currentfile));
        }
        
        if (options.opt & MPG321_REMOTE_PLAY && status == MPG321_STOPPED)
        {
            clear_remote_file(pl);
        }

        mad_decoder_finish(&decoder);

        if (quit_now)
            break;

        if (playbuf.frames)
             free(playbuf.frames);

        if (playbuf.times)
            free(playbuf.times);
            
        if (playbuf.fd == -1)
        {
            munmap(playbuf.buf, playbuf.length);
        }

        else
        {
            free(playbuf.buf);
            if (playbuf.fd != fileno(stdin)) 
                close(playbuf.fd);
        }
    }

    if(playdevice)
        ao_close(playdevice);

    ao_shutdown();

#if defined(RAW_SUPPORT) || defined(HTTP_SUPPORT) || defined(FTP_SUPPORT) 
    if(fd) close(fd);
#endif

    return(0);
}