Hi List,<br><br>I recently was assigned a task to port FLAC Encoder to our embedded platform. Thanks to OO-like design of the libFLAC and throught documentation, that porting went like a charm. I had some problems with chmod/chown like routines while porting but I was able to safely remove that piece of code without any trouble. <br>
<br>I have observed that the my application FLAC Encoder failes in restartability test after about 1500 restarts. Narrowing down the problem shows that I am having problem with multiple calls of FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair() and/or FLAC__metadata_object_vorbiscomment_append_comment() routines, i.e. If I have vorbis comment in my metadata with copy flag == true, my application&#39;s restartability is affected. To test my observation, I took the simple encoder example available with the FLAC package and added a couple of vorbis comments in it as follows,<br>
<br><br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">#if HAVE_CONFIG_H<br>#&nbsp; include &lt;config.h&gt;<br>#endif<br><br>#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>#include &lt;string.h&gt;<br>#include &quot;FLAC_metadata.h&quot;<br>#include &quot;FLAC_stream_encoder.h&quot;<br><br>static char outFileName[256] = {&quot;encAudio.flac&quot;};<br>static unsigned char FLAC_tagTitle[] = {&quot;Title&quot;};<br>
static const unsigned char FLAC_tagArtist[] = {&quot;Artist&quot;};<br>static const unsigned char FLAC_tagAlbum[] = {&quot;Album&quot;};<br>static const unsigned char FLAC_tagYear[] = {&quot;2008&quot;};<br>static const unsigned char FLAC_tagGenre[] = {&quot;Audio Track&quot;};<br>
static const unsigned char defFileName[16] = {&quot;encAUDIO.flac&quot;};<br><br>static void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);<br>
<br>#define READSIZE 1024<br><br>static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */<br>static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */<br>
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];<br><br>int main(int argc, char *argv[])<br>{<br>&nbsp;&nbsp;&nbsp; FLAC__bool ok = true;<br>&nbsp;&nbsp;&nbsp; FLAC__StreamEncoder *encoder = 0;<br>&nbsp;&nbsp;&nbsp; FLAC__StreamEncoderInitStatus init_status;<br>
&nbsp;&nbsp;&nbsp; FLAC__StreamMetadata *metadata[2];<br>&nbsp;&nbsp;&nbsp; FLAC__StreamMetadata_VorbisComment_Entry entry;<br>&nbsp;&nbsp;&nbsp; FILE *fin;<br>&nbsp;&nbsp;&nbsp; unsigned sample_rate = 0;<br>&nbsp;&nbsp;&nbsp; unsigned channels = 0;<br>&nbsp;&nbsp;&nbsp; unsigned bps = 0;<br><br>&nbsp;&nbsp;&nbsp; if(argc != 3) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;usage: %s infile.wav outfile.flac\n&quot;, argv[0]);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; if((fin = fopen(argv[1], &quot;rb&quot;)) == NULL) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;ERROR: opening %s for output\n&quot;, argv[1]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; /* read wav header and validate it */<br>&nbsp;&nbsp;&nbsp; if(<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fread(buffer, 1, 44, fin) != 44 ||<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcmp(buffer, &quot;RIFF&quot;, 4) ||<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcmp(buffer+8, &quot;WAVEfmt \020\000\000\000\001\000\002\000&quot;, 16) ||<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcmp(buffer+32, &quot;\004\000\020\000data&quot;, 8)<br>&nbsp;&nbsp;&nbsp; ) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed\n&quot;);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fclose(fin);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; sample_rate = ((((((unsigned)buffer[27] &lt;&lt; 8) | buffer[26]) &lt;&lt; 8) | buffer[25]) &lt;&lt; 8) | buffer[24];<br>&nbsp;&nbsp;&nbsp; printf(&quot;sampleRate:%d\n&quot;, sample_rate);<br>&nbsp;&nbsp;&nbsp; channels = 2;<br>
&nbsp;&nbsp;&nbsp; bps = 16;<br>&nbsp;&nbsp;&nbsp; total_samples = (((((((unsigned)buffer[43] &lt;&lt; 8) | buffer[42]) &lt;&lt; 8) | buffer[41]) &lt;&lt; 8) | buffer[40]) / 4;<br>&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; /* allocate the encoder */<br>&nbsp;&nbsp;&nbsp; if((encoder = FLAC__stream_encoder_new()) == NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;ERROR: allocating encoder\n&quot;);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fclose(fin);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_verify(encoder, true);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_compression_level(encoder, 5);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_channels(encoder, channels);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);<br><br>&nbsp;&nbsp;&nbsp; if(&nbsp;&nbsp; (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ok = false;<br><br>&nbsp;&nbsp;&nbsp;&nbsp; metadata[0]-&gt;length = 512; /* set the padding length */<br>#if BUGGY<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&amp;entry, &quot;TITLE&quot;, FLAC_tagTitle);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_append_comment(metadata[1], entry, /*copy=*/true);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&amp;entry, &quot;ARTIST&quot;, FLAC_tagArtist);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_append_comment(metadata[1], entry, /*copy=*/true);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&amp;entry, &quot;ALBUM&quot;, FLAC_tagAlbum);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_append_comment(metadata[1], entry, /*copy=*/true);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&amp;entry, &quot;GENRE&quot;, FLAC_tagGenre);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_append_comment(metadata[1], entry, /*copy=*/true);<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&amp;entry, &quot;DATE&quot;, FLAC_tagYear);<br>
&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__metadata_object_vorbiscomment_append_comment(metadata[1], entry, /*copy=*/true);<br>#endif&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; if (!FLAC__stream_encoder_set_metadata(encoder, metadata, 2))<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return FLAC__STREAM_ENCODER_CLIENT_ERROR;<br>
<br>&nbsp;&nbsp;&nbsp; /* initialize encoder */<br>&nbsp;&nbsp;&nbsp; if(ok) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; init_status = FLAC__stream_encoder_init_file(encoder, argv[2], progress_callback, /*client_data=*/NULL);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;ERROR: initializing encoder: %s\n&quot;, FLAC__StreamEncoderInitStatusString[init_status]);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ok = false;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; /* read blocks of samples from WAVE file and feed to encoder */<br>
&nbsp;&nbsp;&nbsp; if(ok) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; size_t left = (size_t)total_samples;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while(ok &amp;&amp; left) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; size_t need = (left&gt;READSIZE? (size_t)READSIZE : (size_t)left);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(fread(buffer, channels*(bps/8), need, fin) != need) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;ERROR: reading from WAVE file\n&quot;);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ok = false;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; size_t i;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for(i = 0; i &lt; need*channels; i++) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* inefficient but simple and works on big- or little-endian machines */<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] &lt;&lt; 8) | (FLAC__int16)buffer[2*i]);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* feed samples to encoder */<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; left -= need;<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>
<br>&nbsp;&nbsp;&nbsp; ok &amp;= FLAC__stream_encoder_finish(encoder);<br><br>&nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;encoding: %s\n&quot;, ok? &quot;succeeded&quot; : &quot;FAILED&quot;);<br>&nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;&nbsp;&nbsp; state: %s\n&quot;, FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]);<br>
<br>&nbsp;&nbsp;&nbsp; /* now that encoding is finished, the metadata can be freed */<br>&nbsp;&nbsp;&nbsp; FLAC__metadata_object_delete(metadata[0]);<br>&nbsp;&nbsp;&nbsp; FLAC__metadata_object_delete(metadata[1]);<br>&nbsp;&nbsp;&nbsp; FLAC__stream_encoder_delete(encoder);<br>&nbsp;&nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; fclose(fin);<br><br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br><br>void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)<br>
{<br>&nbsp;&nbsp;&nbsp; (void)encoder, (void)client_data;<br><br>#ifdef _MSC_VER<br>&nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;wrote %I64u bytes, %I64u/%u samples, %u/%u frames\n&quot;, bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);<br>
#else<br>&nbsp;&nbsp;&nbsp; fprintf(stderr, &quot;wrote %llu bytes, %llu/%u samples, %u/%u frames\n&quot;, bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);<br>#endif<br>}<br></blockquote><br>Then I compiled it with -g option and fed it to valgrind using tool=memcheck. and here is the output of Valgrind,<br>
<br><blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">... wrote 634814 bytes, 292570/292570 samples, 72/72 frames<br>encoding: succeeded<br>&nbsp;&nbsp; state: FLAC__STREAM_ENCODER_UNINITIALIZED<br>
==21449== <br>==21449== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 1)<br>==21449== malloc/free: in use at exit: 97 bytes in 5 blocks.<br>==21449== malloc/free: <b>78 allocs</b>, <b>73 frees</b>, 477,278 bytes allocated.<br>
==21449== For counts of detected errors, rerun with: -v<br>==21449== searching for pointers to 5 not-freed blocks.<br>==21449== checked 67,296 bytes.<br>==21449== <br>==21449== 97 bytes in 5 blocks are definitely lost in loss record 1 of 1<br>
==21449==&nbsp;&nbsp;&nbsp; at 0x401A826: malloc (vg_replace_malloc.c:149)<br>==21449==&nbsp;&nbsp;&nbsp; by 0x804C66F: FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair (in /home/XXX/workspace/FLACEnc/FLACEncoder)<br>==21449==&nbsp;&nbsp;&nbsp; by 0x80488AC: (within /home/XXX/workspace/FLACEnc/FLACEncoder)<br>
==21449== <br>==21449== LEAK SUMMARY:<br>==21449==&nbsp;&nbsp;&nbsp; <b>definitely lost: 97 bytes in 5 blocks.</b><br>==21449==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; possibly lost: 0 bytes in 0 blocks.<br>==21449==&nbsp;&nbsp;&nbsp; still reachable: 0 bytes in 0 blocks.<br>==21449==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppressed: 0 bytes in 0 blocks.<br>
</blockquote><br>Above results are produced with libFLAC(vanilla) available with FLAC v1.2.1 on a linux distro.<br><br>I have observed that If I use VORBIS_COMMENT metadata with copy == true, I get memory leaks, but with copy==false, I DONT get memory leaks.<br>
<br>I guess by asking the question, I have solved my problem of leak but the question itself stands still. <br><br>I dont know if my question is right or not,<br>&quot;is this behavior desired, should we get a memory leak if copy == true, when should we set copy and when should we unset it&quot;?<br>
<br>Just&nbsp; before pressing Send button, I also tested If this behavior is useful for String pointers to the FLAC__metadata_object_vorbiscomment_append_comment() routine but It didnt help the leak. <br><br>Thanks all for your time.<br>
<br>Regards,<br>Nabsha<br>