operations_shorthand_seektable.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:8k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* metaflac - Command-line FLAC metadata editor
  2.  * Copyright (C) 2001,2002,2003,2004,2005  Josh Coalson
  3.  *
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  */
  18. #include "utils.h"
  19. #include "FLAC/assert.h"
  20. #include "FLAC/file_decoder.h"
  21. #include "FLAC/metadata.h"
  22. #include "share/grabbag.h"
  23. static FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write);
  24. FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write)
  25. {
  26. FLAC__bool ok = true, found_seektable_block = false;
  27. FLAC__StreamMetadata *block = 0;
  28. FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
  29. FLAC__uint64 total_samples = 0;
  30. unsigned sample_rate = 0;
  31. if(0 == iterator)
  32. die("out of memory allocating iterator");
  33. FLAC__metadata_iterator_init(iterator, chain);
  34. do {
  35. block = FLAC__metadata_iterator_get_block(iterator);
  36. if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
  37. sample_rate = block->data.stream_info.sample_rate;
  38. total_samples = block->data.stream_info.total_samples;
  39. }
  40. else if(block->type == FLAC__METADATA_TYPE_SEEKTABLE)
  41. found_seektable_block = true;
  42. } while(!found_seektable_block && FLAC__metadata_iterator_next(iterator));
  43. if(total_samples == 0) {
  44. fprintf(stderr, "%s: ERROR: cannot add seekpoints because STREAMINFO block does not specify total_samplesn", filename);
  45. return false;
  46. }
  47. if(!found_seektable_block) {
  48. /* create a new block */
  49. block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
  50. if(0 == block)
  51. die("out of memory allocating SEEKTABLE block");
  52. while(FLAC__metadata_iterator_prev(iterator))
  53. ;
  54. if(!FLAC__metadata_iterator_insert_block_after(iterator, block)) {
  55. print_error_with_chain_status(chain, "%s: ERROR: adding new SEEKTABLE block to metadata", filename);
  56. FLAC__metadata_object_delete(block);
  57. return false;
  58. }
  59. /* iterator is left pointing to new block */
  60. FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == block);
  61. }
  62. FLAC__metadata_iterator_delete(iterator);
  63. FLAC__ASSERT(0 != block);
  64. FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
  65. if(!grabbag__seektable_convert_specification_to_template(specification, /*only_explicit_placeholders=*/false, total_samples, sample_rate, block, /*spec_has_real_points=*/0)) {
  66. fprintf(stderr, "%s: ERROR (internal) preparing seektable with seekpointsn", filename);
  67. return false;
  68. }
  69. ok = populate_seekpoint_values(filename, block, needs_write);
  70. if(ok)
  71. (void) FLAC__format_seektable_sort(&block->data.seek_table);
  72. return ok;
  73. }
  74. /*
  75.  * local routines
  76.  */
  77. typedef struct {
  78. FLAC__StreamMetadata_SeekTable *seektable_template;
  79. FLAC__uint64 samples_written;
  80. FLAC__uint64 audio_offset, last_offset;
  81. unsigned first_seekpoint_to_check;
  82. FLAC__bool error_occurred;
  83. FLAC__StreamDecoderErrorStatus error_status;
  84. } ClientData;
  85. static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
  86. {
  87. ClientData *cd = (ClientData*)client_data;
  88. (void)buffer;
  89. FLAC__ASSERT(0 != cd);
  90. if(!cd->error_occurred && cd->seektable_template->num_points > 0) {
  91. const unsigned blocksize = frame->header.blocksize;
  92. const FLAC__uint64 frame_first_sample = cd->samples_written;
  93. const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
  94. FLAC__uint64 test_sample;
  95. unsigned i;
  96. for(i = cd->first_seekpoint_to_check; i < cd->seektable_template->num_points; i++) {
  97. test_sample = cd->seektable_template->points[i].sample_number;
  98. if(test_sample > frame_last_sample) {
  99. break;
  100. }
  101. else if(test_sample >= frame_first_sample) {
  102. cd->seektable_template->points[i].sample_number = frame_first_sample;
  103. cd->seektable_template->points[i].stream_offset = cd->last_offset - cd->audio_offset;
  104. cd->seektable_template->points[i].frame_samples = blocksize;
  105. cd->first_seekpoint_to_check++;
  106. /* DO NOT: "break;" and here's why:
  107.  * The seektable template may contain more than one target
  108.  * sample for any given frame; we will keep looping, generating
  109.  * duplicate seekpoints for them, and we'll clean it up later,
  110.  * just before writing the seektable back to the metadata.
  111.  */
  112. }
  113. else {
  114. cd->first_seekpoint_to_check++;
  115. }
  116. }
  117. cd->samples_written += blocksize;
  118. if(!FLAC__file_decoder_get_decode_position(decoder, &cd->last_offset))
  119. return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  120. return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
  121. }
  122. else
  123. return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
  124. }
  125. static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
  126. {
  127. (void)decoder, (void)metadata, (void)client_data;
  128. FLAC__ASSERT(0); /* we asked to skip all metadata */
  129. }
  130. static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
  131. {
  132. ClientData *cd = (ClientData*)client_data;
  133. (void)decoder;
  134. FLAC__ASSERT(0 != cd);
  135. if(!cd->error_occurred) { /* don't let multiple errors overwrite the first one */
  136. cd->error_occurred = true;
  137. cd->error_status = status;
  138. }
  139. }
  140. FLAC__bool populate_seekpoint_values(const char *filename, FLAC__StreamMetadata *block, FLAC__bool *needs_write)
  141. {
  142. FLAC__FileDecoder *decoder;
  143. ClientData client_data;
  144. FLAC__bool ok = true;
  145. FLAC__ASSERT(0 != block);
  146. FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_SEEKTABLE);
  147. client_data.seektable_template = &block->data.seek_table;
  148. client_data.samples_written = 0;
  149. /* client_data.audio_offset must be determined later */
  150. client_data.first_seekpoint_to_check = 0;
  151. client_data.error_occurred = false;
  152. decoder = FLAC__file_decoder_new();
  153. if(0 == decoder) {
  154. fprintf(stderr, "%s: ERROR (--add-seekpoint) creating the decoder instancen", filename);
  155. return false;
  156. }
  157. FLAC__file_decoder_set_md5_checking(decoder, false);
  158. FLAC__file_decoder_set_filename(decoder, filename);
  159. FLAC__file_decoder_set_metadata_ignore_all(decoder);
  160. FLAC__file_decoder_set_write_callback(decoder, write_callback_);
  161. FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
  162. FLAC__file_decoder_set_error_callback(decoder, error_callback_);
  163. FLAC__file_decoder_set_client_data(decoder, &client_data);
  164. if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
  165. fprintf(stderr, "%s: ERROR (--add-seekpoint) initializing the decoder instance (%s)n", filename, FLAC__file_decoder_get_resolved_state_string(decoder));
  166. ok = false;
  167. }
  168. if(ok && !FLAC__file_decoder_process_until_end_of_metadata(decoder)) {
  169. fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)n", filename, FLAC__file_decoder_get_resolved_state_string(decoder));
  170. ok = false;
  171. }
  172. if(ok && !FLAC__file_decoder_get_decode_position(decoder, &client_data.audio_offset)) {
  173. fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding filen", filename);
  174. ok = false;
  175. }
  176. client_data.last_offset = client_data.audio_offset;
  177. if(ok && !FLAC__file_decoder_process_until_end_of_file(decoder)) {
  178. fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%s)n", filename, FLAC__file_decoder_get_resolved_state_string(decoder));
  179. ok = false;
  180. }
  181. if(ok && client_data.error_occurred) {
  182. fprintf(stderr, "%s: ERROR (--add-seekpoint) decoding file (%u:%s)n", filename, (unsigned)client_data.error_status, FLAC__StreamDecoderErrorStatusString[client_data.error_status]);
  183. ok = false;
  184. }
  185. *needs_write = true;
  186. FLAC__file_decoder_delete(decoder);
  187. return ok;
  188. }