📄 vorbis.c
字号:
/******************************************************************************* vorbis.c libquicktime - A library for reading and writing quicktime/avi/mp4 files. http://libquicktime.sourceforge.net Copyright (C) 2002 Heroine Virtual Ltd. Copyright (C) 2002-2007 Members of the libquicktime project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*******************************************************************************/ #include "lqt_private.h"#include "qtvorbis.h"#define LQT_LIBQUICKTIME#include <quicktime/lqt_codecapi.h>#include <vorbis/vorbisenc.h>#include <stdlib.h>#include <string.h>#define LOG_DOMAIN "vorbis"typedef struct{/* Common stuff */ float ** sample_buffer; int sample_buffer_alloc; /* Encoder stuff */ int max_bitrate; int nominal_bitrate; int min_bitrate; int use_vbr; int write_OVHS; int encode_initialized; ogg_stream_state enc_os; ogg_page enc_og; uint8_t * enc_header; int enc_header_len; int header_written;ogg_packet enc_op; vorbis_info enc_vi; vorbis_comment enc_vc; vorbis_dsp_state enc_vd; vorbis_block enc_vb;// int64_t last_granulepos;// Number of samples written to disk int encoded_samples; int enc_samples_in_buffer; int chunk_started; quicktime_atom_t chunk_atom;/* Decoder stuff */ ogg_sync_state dec_oy; /* sync and verify incoming physical bitstream */ ogg_stream_state dec_os; /* take physical pages, weld into a logical stream of packets */ ogg_page dec_og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet dec_op; /* one raw packet of data for decode */ vorbis_info dec_vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment dec_vc; /* struct that stores all the bitstream user comments */ vorbis_dsp_state dec_vd; /* central working state for the packet->PCM decoder */ vorbis_block dec_vb; /* local working space for packet->PCM decode */ int decode_initialized; int stream_initialized; /* Buffer for the entire chunk */ uint8_t * chunk_buffer; int chunk_buffer_alloc; int bytes_in_chunk_buffer; /* Start and end positions of the sample buffer */ int64_t sample_buffer_start; int64_t sample_buffer_end;// Number of last sample relative to file int64_t output_position;// Number of last sample relative to output buffer long output_end;// Number of samples in output buffer long output_size;// Number of samples allocated in output buffer long output_allocated;// Current reading position in file int64_t chunk;// Number of samples decoded in the current chunk int chunk_samples; int header_read; } quicktime_vorbis_codec_t;/* =================================== public for vorbis */static int delete_codec(quicktime_audio_map_t *atrack) { quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)atrack->codec)->priv; int i; if(codec->encode_initialized) { ogg_stream_clear(&codec->enc_os); vorbis_block_clear(&codec->enc_vb); vorbis_dsp_clear(&codec->enc_vd); vorbis_comment_clear(&codec->enc_vc); vorbis_info_clear(&codec->enc_vi); } if(codec->decode_initialized) { ogg_stream_clear(&codec->dec_os); vorbis_block_clear(&codec->dec_vb); vorbis_dsp_clear(&codec->dec_vd); vorbis_comment_clear(&codec->dec_vc); vorbis_info_clear(&codec->dec_vi); } if(codec->sample_buffer) { for(i = 0; i < atrack->channels; i++) free(codec->sample_buffer[i]); free(codec->sample_buffer); } if(codec->chunk_buffer) free(codec->chunk_buffer); if(codec->enc_header) free(codec->enc_header); free(codec); return 0; }static int next_chunk(quicktime_t * file, int track) { int i; int num_packets; int samples; int chunk_size; char * buffer; uint8_t * header; uint32_t header_len; quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; if(!codec->header_read) /* Try OVHS atom */ { header = quicktime_wave_get_user_atom(track_map->track, "OVHS", &header_len); if(header) { lqt_log(file, LQT_LOG_DEBUG, LOG_DOMAIN, "Using OVHS Atom, %d bytes", header_len-8); buffer = ogg_sync_buffer(&codec->dec_oy, header_len-8); memcpy(buffer, header + 8, header_len-8); ogg_sync_wrote(&codec->dec_oy, header_len-8); return 1; } } if(lqt_audio_is_vbr(file, track)) { num_packets = lqt_audio_num_vbr_packets(file, track, track_map->current_chunk, &samples); if(!num_packets) return 0; for(i = 0; i < num_packets; i++) { chunk_size = lqt_audio_read_vbr_packet(file, track, track_map->current_chunk, i, &(codec->chunk_buffer), &(codec->chunk_buffer_alloc), &samples); buffer = ogg_sync_buffer(&codec->dec_oy, chunk_size); memcpy(buffer, codec->chunk_buffer, chunk_size); ogg_sync_wrote(&codec->dec_oy, chunk_size); } } else { chunk_size = lqt_read_audio_chunk(file, track, track_map->current_chunk, &(codec->chunk_buffer), &(codec->chunk_buffer_alloc), (int*)0); if(chunk_size <= 0) { return 0; } buffer = ogg_sync_buffer(&codec->dec_oy, chunk_size); memcpy(buffer, codec->chunk_buffer, chunk_size); ogg_sync_wrote(&codec->dec_oy, chunk_size); } track_map->current_chunk++; return 1; }static int next_page(quicktime_t * file, int track) { quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; int result = 0; while(result < 1) { result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og); if(result == 0) { if(!next_chunk(file, track)) { return 0; } } else { if(!codec->stream_initialized) { ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og)); codec->stream_initialized = 1; } ogg_stream_pagein(&codec->dec_os, &codec->dec_og); } } return 1; }static int next_packet(quicktime_t * file, int track) { quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; int result = 0; while(result < 1) { result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op); if(result == 0) { if(!next_page(file, track)) return 0; } } return 1; }static float ** alloc_sample_buffer(float ** old, int channels, int samples, int * sample_buffer_alloc) { int i; if(!old) { old = calloc(channels, sizeof(*(old))); } if(*sample_buffer_alloc < samples) { *sample_buffer_alloc = samples + 256; for(i = 0; i < channels; i++) { old[i] = realloc(old[i], (*sample_buffer_alloc) * sizeof(float)); } } return old; }static int decode_frame(quicktime_t * file, int track) { int i; float ** channels; int samples_decoded = 0; quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; while(1) { samples_decoded = vorbis_synthesis_pcmout(&codec->dec_vd, &(channels)); if(samples_decoded > 0) break; /* Decode new data */ if(!next_packet(file, track)) { return 0; } if(vorbis_synthesis(&codec->dec_vb, &codec->dec_op) == 0) { vorbis_synthesis_blockin(&codec->dec_vd, &codec->dec_vb); } } codec->sample_buffer = alloc_sample_buffer(codec->sample_buffer, file->atracks[track].channels, codec->sample_buffer_end - codec->sample_buffer_start + samples_decoded, &(codec->sample_buffer_alloc)); for(i = 0; i < track_map->channels; i++) { memcpy(codec->sample_buffer[i] + (int)(codec->sample_buffer_end - codec->sample_buffer_start), channels[i], samples_decoded * sizeof(float)); } vorbis_synthesis_read(&codec->dec_vd, samples_decoded); codec->sample_buffer_end += samples_decoded; return 1; }static int decode(quicktime_t *file, void * _output, long samples, int track) { int i, j; int64_t chunk_sample; /* For seeking only */ quicktime_audio_map_t *track_map = &(file->atracks[track]); quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv; // int64_t total_samples; int samples_decoded; int samples_to_skip; int samples_to_move; int samples_copied; float * output; if(!_output) /* Global initialization */ { return 0; } /* Initialize codec */ if(!codec->decode_initialized) { codec->decode_initialized = 1; ogg_sync_init(&codec->dec_oy); /* Now we can read pages */ vorbis_info_init(&codec->dec_vi); vorbis_comment_init(&codec->dec_vc); if(!next_page(file, track)) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: next page failed"); return 0; } if(!next_packet(file, track)) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: next packet failed"); return 0; } if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: vorbis_synthesis_headerin: not a vorbis header"); return 0; } if(!next_packet(file, track)) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: next packet failed"); return 0; } if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: vorbis_synthesis_headerin: not a vorbis header"); return 0; } if(!next_packet(file, track)) return 0; if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0) { lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "decode: vorbis_synthesis_headerin: not a vorbis header"); return 0; } codec->header_read = 1; vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi); vorbis_block_init(&codec->dec_vd, &codec->dec_vb); } /* Check if we have to reposition the stream */ if(file->atracks[track].last_position != file->atracks[track].current_position) { /* Get the next chunk */ if(lqt_audio_is_vbr(file, track)) lqt_chunk_of_sample_vbr(&chunk_sample, &(track_map->current_chunk),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -