Audio-Scan
view release on metacpan or search on metacpan
my_hv_store( info, "lame_preset", newSVpv( presets_v[mp3->xing_frame->lame_preset], 0 ) );
}
}
else if (mp3->xing_frame->lame_preset >= 1000 && mp3->xing_frame->lame_preset <= 1007) {
mp3->xing_frame->lame_preset -= 1000;
if ( presets_old[mp3->xing_frame->lame_preset] ) {
my_hv_store( info, "lame_preset", newSVpv( presets_old[mp3->xing_frame->lame_preset], 0 ) );
}
}
}
if (mp3->vbr == ABR || mp3->vbr == VBR) {
my_hv_store( info, "vbr", newSViv(1) );
}
// DLNA profile detection
if (_is_mp3x_profile(mp3))
my_hv_store( info, "dlna_profile", newSVpvn( "MP3X", 4 ) );
else if (_is_mp3_profile(mp3))
my_hv_store( info, "dlna_profile", newSVpvn( "MP3", 3 ) );
out:
return mp3;
}
int
mp3_find_frame(PerlIO *infile, char *file, int offset)
{
Buffer mp3_buf;
unsigned char *bptr;
unsigned int buf_size;
struct mp3frame frame;
int frame_offset = -1;
HV *info = newHV();
mp3info *mp3 = _mp3_parse(infile, file, info);
buffer_init(&mp3_buf, MP3_BLOCK_SIZE);
if (!mp3->song_length_ms)
goto out;
// (undocumented) If offset is negative, treat it as an absolute file offset in bytes
// This is a bit ugly but avoids the need to write an entirely new method
if (offset < 0) {
frame_offset = abs(offset);
if (frame_offset < mp3->audio_offset) {
// Force offset to be at least audio_offset, so we don't end up in an ID3 tag
frame_offset = mp3->audio_offset;
}
DEBUG_TRACE("find_frame: using absolute offset value %d\n", frame_offset);
}
else {
if (offset >= mp3->song_length_ms) {
goto out;
}
// Use Xing TOC if available
if ( mp3->xing_frame->has_toc ) {
float percent;
uint8_t ipercent;
uint16_t tva;
uint16_t tvb;
float tvx;
percent = (offset * 1.0 / mp3->song_length_ms) * 100;
ipercent = (int)percent;
if (ipercent > 99)
ipercent = 99;
// Interpolate between 2 TOC points
tva = mp3->xing_frame->xing_toc[ipercent];
if (ipercent < 99) {
tvb = mp3->xing_frame->xing_toc[ipercent + 1];
}
else {
tvb = 256;
}
tvx = tva + (tvb - tva) * (percent - ipercent);
frame_offset = (int)((1.0/256.0) * tvx * mp3->xing_frame->xing_bytes);
frame_offset += mp3->audio_offset;
// Don't return offset == audio_offset, because that would be the Xing frame
if (frame_offset == mp3->audio_offset) {
DEBUG_TRACE("find_frame: frame_offset == audio_offset, skipping to next frame\n");
frame_offset += 1;
}
DEBUG_TRACE("find_frame: using Xing TOC, song_length_ms: %d, percent: %f, tva: %d, tvb: %d, tvx: %f, frame offset: %d\n",
mp3->song_length_ms, percent, tva, tvb, tvx, frame_offset
);
}
else {
// calculate offset using bitrate
float bytes_per_ms = mp3->bitrate / 8.0;
frame_offset = (int)(bytes_per_ms * offset);
frame_offset += mp3->audio_offset;
DEBUG_TRACE("find_frame: using bitrate %d, bytes_per_ms: %f, frame offset: %d\n", mp3->bitrate, bytes_per_ms, frame_offset);
}
}
// If frame_offset is too near the end of the file we won't find a valid frame
// so require offset to be at least 1000 bytes from the end of the file
// XXX this would be more accurate if we determined max_frame_len
if ((mp3->file_size - frame_offset) < 1000) {
frame_offset -= 1000 - (mp3->file_size - frame_offset);
if (frame_offset < 0)
frame_offset = 0;
DEBUG_TRACE("find_frame: offset too close to end of file, adjusted to %d\n", frame_offset);
}
PerlIO_seek(infile, frame_offset, SEEK_SET);
if ( !_check_buf(infile, &mp3_buf, 4, MP3_BLOCK_SIZE) ) {
frame_offset = -1;
goto out;
}
bptr = (unsigned char *)buffer_ptr(&mp3_buf);
buf_size = buffer_len(&mp3_buf);
// Find 0xFF sync and verify it's a valid mp3 frame header
while (1) {
if (
buf_size < 4
||
( bptr[0] == 0xFF && !_decode_mp3_frame( bptr, &frame ) )
) {
break;
}
bptr++;
buf_size--;
}
if (buf_size >= 4) {
frame_offset += buffer_len(&mp3_buf) - buf_size;
DEBUG_TRACE("find_frame: frame_offset: %d\n", frame_offset);
}
else {
// Didn't find a valid frame, probably too near the end of the file
DEBUG_TRACE("find_frame: did not find a valid frame\n");
frame_offset = -1;
}
out:
buffer_free(&mp3_buf);
( run in 0.581 second using v1.01-cache-2.11-cpan-39bf76dae61 )