<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Max -<div class=""><br class=""></div><div class="">Good suggestion...I’ll try to create a minimal implementation to post.</div><div class=""><br class=""></div><div class="">But now my questions may be a bit more educated. I’m posting what I’ve learned so far, so that perhaps this will help others, or allow others to provide some more useful feedback...</div><div class=""><br class=""></div><div class="">There’s a *lot* of info on command-line ffmpeg usage, with details on controlling quality for x264 encoding. So I was convinced my goal is achievable. The problem was that I was not aware of the mapping between ffmpeg command-line parameters and the API. Eventually, I looked at the source for FFmpeg’s libx264.c (<a href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c_source.html" class="">https://www.ffmpeg.org/doxygen/2.4/libx264_8c_source.html</a>), and found that there’s a rather large set of parameters/controls/options for x264 that are not part of the general encoder API:</div><div class=""><br class=""></div><div class=""><div class="line" style="line-height: 1; min-height: 13px; white-space: pre-wrap; word-wrap: break-word; text-indent: -53px; padding-left: 53px; padding-bottom: 0px; margin: 0px; transition: background-color 0.5s, box-shadow; -webkit-transition: background-color 0.5s, box-shadow; background-color: rgb(251, 252, 253);"><font face="Courier" class=""><span class="lineno" style="padding-right: 4px; text-align: right; border-right-width: 2px; border-right-style: solid; border-right-color: rgb(0, 255, 0); background-color: rgb(232, 232, 232); white-space: pre;"><a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#a384ff94b5139f441c282c9b4c7b985e6" style="color: rgb(70, 101, 162); text-decoration: none; background-color: rgb(216, 216, 216);">  754</a></span> <span class="preprocessor" style="color: rgb(128, 96, 32);"></span><span class="keyword" style="color: rgb(0, 128, 0);">static</span> <span class="keyword" style="color: rgb(0, 128, 0);">const</span> <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/structAVOption.html" title="AVOption." style="color: rgb(70, 101, 162); text-decoration: none;">AVOption</a> <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/ffmpeg_8h.html#abdbaa7127ef32aa4c435f3c609b4c2cd" style="color: rgb(70, 101, 162); text-decoration: none;">options</a>[] = {</font></div><div class="line" style="line-height: 1; min-height: 13px; white-space: pre-wrap; word-wrap: break-word; text-indent: -53px; padding-left: 53px; padding-bottom: 0px; margin: 0px; transition: background-color 0.5s, box-shadow; -webkit-transition: background-color 0.5s, box-shadow; background-color: rgb(251, 252, 253);"><font face="Courier" class=""><a name="l00755" style="color: rgb(61, 87, 140);" class=""></a><span class="lineno" style="padding-right: 4px; text-align: right; border-right-width: 2px; border-right-style: solid; border-right-color: rgb(0, 255, 0); background-color: rgb(232, 232, 232); white-space: pre;">  755</span>     { <span class="stringliteral" style="color: rgb(0, 32, 128);">"preset"</span>,        <span class="stringliteral" style="color: rgb(0, 32, 128);">"Set the encoding preset (cf. x264 --fullhelp)"</span>,   <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#ad12dce0a7bf9d908b172a28155b3d261" style="color: rgb(70, 101, 162); text-decoration: none;">OFFSET</a>(<a class="code" href="https://www.ffmpeg.org/doxygen/2.4/vf__curves_8c.html#a7f1bb62735b2e1288baece1f7e14514f" style="color: rgb(70, 101, 162); text-decoration: none;">preset</a>),        <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/group__avoptions.html#ggabd75aa30eb8ad6387672df9a1fa79444afadddce95ad3b690dd38644b458b96c4" style="color: rgb(70, 101, 162); text-decoration: none;">AV_OPT_TYPE_STRING</a>, { .str = <span class="stringliteral" style="color: rgb(0, 32, 128);">"medium"</span> }, 0, 0, <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#a3dcf4acb9f7d9c57f43802a9a1ac4ee6" style="color: rgb(70, 101, 162); text-decoration: none;">VE</a>},</font></div><div class="line" style="line-height: 1; min-height: 13px; white-space: pre-wrap; word-wrap: break-word; text-indent: -53px; padding-left: 53px; padding-bottom: 0px; margin: 0px; transition: background-color 0.5s, box-shadow; -webkit-transition: background-color 0.5s, box-shadow; background-color: rgb(251, 252, 253);"><font face="Courier" class=""><a name="l00756" style="color: rgb(61, 87, 140);" class=""></a><span class="lineno" style="padding-right: 4px; text-align: right; border-right-width: 2px; border-right-style: solid; border-right-color: rgb(0, 255, 0); background-color: rgb(232, 232, 232); white-space: pre;">  756</span>     { <span class="stringliteral" style="color: rgb(0, 32, 128);">"tune"</span>,          <span class="stringliteral" style="color: rgb(0, 32, 128);">"Tune the encoding params (cf. x264 --fullhelp)"</span>,  <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#ad12dce0a7bf9d908b172a28155b3d261" style="color: rgb(70, 101, 162); text-decoration: none;">OFFSET</a>(tune),          <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/group__avoptions.html#ggabd75aa30eb8ad6387672df9a1fa79444afadddce95ad3b690dd38644b458b96c4" style="color: rgb(70, 101, 162); text-decoration: none;">AV_OPT_TYPE_STRING</a>, { 0 }, 0, 0, <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#a3dcf4acb9f7d9c57f43802a9a1ac4ee6" style="color: rgb(70, 101, 162); text-decoration: none;">VE</a>},</font></div><div class="line" style="line-height: 1; min-height: 13px; white-space: pre-wrap; word-wrap: break-word; text-indent: -53px; padding-left: 53px; padding-bottom: 0px; margin: 0px; transition: background-color 0.5s, box-shadow; -webkit-transition: background-color 0.5s, box-shadow; background-color: rgb(251, 252, 253);"><font face="Courier" class=""><a name="l00757" style="color: rgb(61, 87, 140);" class=""></a><span class="lineno" style="padding-right: 4px; text-align: right; border-right-width: 2px; border-right-style: solid; border-right-color: rgb(0, 255, 0); background-color: rgb(232, 232, 232); white-space: pre;">  757</span>     { <span class="stringliteral" style="color: rgb(0, 32, 128);">"profile"</span>,       <span class="stringliteral" style="color: rgb(0, 32, 128);">"Set profile restrictions (cf. x264 --fullhelp) "</span>, <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#ad12dce0a7bf9d908b172a28155b3d261" style="color: rgb(70, 101, 162); text-decoration: none;">OFFSET</a>(profile),       <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/group__avoptions.html#ggabd75aa30eb8ad6387672df9a1fa79444afadddce95ad3b690dd38644b458b96c4" style="color: rgb(70, 101, 162); text-decoration: none;">AV_OPT_TYPE_STRING</a>, { 0 }, 0, 0, <a class="code" href="https://www.ffmpeg.org/doxygen/2.4/libx264_8c.html#a3dcf4acb9f7d9c57f43802a9a1ac4ee6" style="color: rgb(70, 101, 162); text-decoration: none;">VE</a>},</font></div></div><div class=""><br class=""></div><div class="">and many more...</div><div class=""><br class=""></div><div class="">Usage is like this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; color: rgb(119, 121, 151);" class=""><font face="Courier" class=""><span style="color: rgb(0, 0, 0);" class="">        </span><span style="color: rgb(88, 126, 168);" class="">av_opt_set</span><span style="color: rgb(0, 0, 0);" class="">(c-></span><span style="color: rgb(88, 126, 168);" class="">priv_data</span><span style="color: rgb(0, 0, 0);" class="">, </span><span style="color: rgb(232, 35, 0);" class="">"crf"</span><span style="color: rgb(0, 0, 0);" class="">, </span><span style="color: rgb(232, 35, 0);" class="">"1"</span><span style="color: rgb(0, 0, 0);" class="">, </span>AV_OPT_SEARCH_CHILDREN<span style="color: rgb(0, 0, 0);" class="">);</span></font></div></div><div class=""><br class=""></div><div class="">Of particular importance for controlling quality are the “crf” (Constant Rate Factor) or “qp” (Quantization Parameter) options, which are named as they are in the command-line ffmpeg (and thus referenced in numerous posts/forums). Notably, “crf” causes variable bitrate, and “qp” causes a constant bitrate.</div><div class=""><br class=""></div><div class="">To avoid repeating what’s in a lot of forum posts, I’ll just note that “crf” defaults to 23, which seems not to be adequate for my purposes (very large images with high-frequency content, used as still images to be encoded). Using smaller values increases quality via increasing the bitrate (and other things?). A “0” value is lossless, but not all profiles support this. A “1” value gives me more sampling than I need; I’ve not played with the value to determine what would be optimal.</div><div class=""><br class=""></div><div class="">I’ve also tried “qp”. Again with smaller values, the quality can be drastically improved. Some forum posts suggest “crf” is a better approach, as it’s adaptive and generally results in smaller files for the same quality results; I found this to be accurate.</div><div class=""><br class=""></div><div class="">So, for both “crf” and “qp”, I can tune the quality by using different values, but the resulting bitrate is determined algorithmically by the encoder. </div><div class=""><br class=""></div><div class="">According to ffmpeg command-line documentation, I should be able to explicitly set the bitrate with the equivalent to the “-b” option or similar, but I’m not able to find this in the AVOptions structure in libx264.c. And, as I’ve stated before, setting the bitrate with the “obvious” encoder API has no effect. It certainly seems like one ought to be able to just force a particular bitrate, but I still don’t know how to do this.</div><div class=""><br class=""></div><div class="">As a practical matter, forcing a particular bitrate may be a non-issue, as dialing in the right “crf” or “qp” value can yield a range of quality levels. But still, it would be nice to know how to do this…</div><div class=""><br class=""></div><div class="">— Philip</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 9, 2015, at 1:10 AM, Max Vlasov <<a href="mailto:max.vlasov@gmail.com" class="">max.vlasov@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Then I'd recommend creating a simple "all in one procedure" example containing all affected codes from your sources to reproduce the problem. Seeing all of them in one place sometimes help determining what the problem is. If the problem still exists and you don't see what is wrong then posting this fragment here might help <br class=""></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Apr 8, 2015 at 10:30 PM, Philip Schneider <span dir="ltr" class=""><<a href="mailto:pjschneider@earthlink.net" target="_blank" class="">pjschneider@earthlink.net</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="">Hi -<div class=""><br class=""></div><div class="">Indeed, that’s what I’m doing. This seems to have solved the same issue for some other folks, but my guess is that some other parameter/setting is necessary, which I don’t have :-(</div><span class="HOEnZb"><font color="#888888" class=""><div class=""><br class=""></div><div class="">— Philip</div></font></span><div class=""><div class="h5"><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Apr 8, 2015, at 6:03 AM, Max Vlasov <<a href="mailto:max.vlasov@gmail.com" target="_blank" class="">max.vlasov@gmail.com</a>> wrote:</div><br class=""><div class=""><div dir="ltr" class="">I think you should set frame pts before avcodec_encode_video2. After avcodec_encode_video2 this value is transferred to the packet by the encoder where it should be converted into the stream time base.<br class=""></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Mon, Apr 6, 2015 at 10:10 PM, Philip Schneider <span dir="ltr" class=""><<a href="mailto:pjschneider@earthlink.net" target="_blank" class="">pjschneider@earthlink.net</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class="">Greetings -<div class=""><br class=""></div><div class="">I’m attempting to encode a sequence of frames with libx264. For testing, I’m using the sample code from <a href="http://www.imc-store.com.au/Articles.asp?ID=276" target="_blank" class="">http://www.imc-store.com.au/Articles.asp?ID=276</a>. This is all pretty vanilla FFmpeg API usage, and is similar to what one might write oneself. It produces correct output with libx264, however the bitrate I specify is not honored at all…</div><div class=""><br class=""></div><div class="">I can set the bitrate (m_AVIMOV_BPS) to whatever number I choose, and the actual bitrate used is some other value:</div><div class=""><span style="color:rgb(195,89,0);font-family:'Panic Sans';white-space:pre-wrap" class="">        </span></div><div class=""><div style="margin:0px" class=""><div style="margin:0px" class=""><span style="font-family:Courier" class=""><span style="white-space:pre-wrap" class="">                </span></span><span style="font-family:Courier;color:rgb(195,89,0)" class="">AVCodec</span><span style="font-family:Courier;color:rgb(88,126,168)" class=""> *m_video_codec </span><span style="font-family:Courier" class="">= </span><span style="font-family:Courier;color:rgb(88,126,168)" class="">avcodec_find_encoder</span><span style="font-family:Courier" class="">(</span><span style="font-family:Courier;color:rgb(88,126,168)" class="">m_fmt</span><span style="font-family:Courier" class="">-></span><span style="font-family:Courier;color:rgb(88,126,168)" class="">video_codec</span><span style="font-family:Courier" class="">);</span></div><div style="color:rgb(88,126,168);margin:0px" class=""><font face="Courier" class=""><span class=""><span style="white-space:pre-wrap" class="">            </span></span><span style="color:#35568a" class="">if</span><span class=""> (!(</span>m_video_codec<span class="">)) {</span></font></div><div style="color:rgb(53,86,138);margin:0px" class=""><font face="Courier" class=""><span class=""><span style="white-space:pre-wrap" class="">             </span>    </span>return<span class="">;</span></font></div><div style="color:rgb(195,89,0);margin:0px" class=""><font face="Courier" class=""><span style="white-space:pre-wrap" class="">          </span>}</font></div><div style="color:rgb(207,135,36);margin:0px" class=""><span style="font-family:Courier" class=""><span style="white-space:pre-wrap" class="">             </span></span><span style="font-family:Courier;color:rgb(195,89,0)" class="">AVStream</span><span style="font-family:Courier" class="">       *st</span><span style="font-family:Courier" class="">  = </span><span style="font-family:Courier;color:rgb(88,126,168)" class="">avformat_new_stream</span><span style="font-family:Courier" class="">(</span><span style="font-family:Courier;color:rgb(88,126,168)" class="">m_oc</span><span style="font-family:Courier" class="">, </span><span style="font-family:Courier;color:rgb(88,126,168)" class="">m_video_codec</span><span style="font-family:Courier" class="">);</span></div><div style="color:rgb(207,135,36);margin:0px" class=""><span style="font-family:Courier;color:rgb(195,89,0);white-space:pre-wrap" class="">           </span><span style="font-family:Courier;color:rgb(195,89,0)" class="">AVCodecContext</span><span style="font-family:Courier" class=""> *m_c</span><span style="font-family:Courier;color:rgb(195,89,0)" class=""> = st-></span><span style="font-family:Courier;color:rgb(88,126,168)" class="">codec</span><span style="font-family:Courier;color:rgb(195,89,0)" class="">;</span></div><div style="color:rgb(195,89,0);margin:0px;min-height:14px" class=""><font face="Courier" class=""><span style="white-space:pre-wrap" class="">         </span><br class=""></font></div><div style="color:rgb(207,135,36);margin:0px" class=""><span style="font-family:Courier" class=""><span style="white-space:pre-wrap" class="">         </span></span><span style="font-family:Courier;color:rgb(88,126,168)" class="">m_c</span><span style="font-family:Courier" class="">-></span><span style="font-family:Courier;color:rgb(88,126,168)" class="">codec_id</span><span style="font-family:Courier" class=""> = </span><span style="font-family:Courier;color:rgb(88,126,168)" class="">m_fmt</span><span style="font-family:Courier" class="">-></span><span style="font-family:Courier;color:rgb(88,126,168)" class="">video_codec</span><span style="font-family:Courier" class="">;</span></div><div style="color:rgb(88,126,168);margin:0px" class=""><font face="Courier" class=""><span class=""><span style="white-space:pre-wrap" class="">           </span></span>m_c<span class="">-></span>bit_rate<span class=""> = </span>m_AVIMOV_BPS<span class="">;</span><span style="color:rgb(207,135,36)" class=""> </span></font></div><div style="font-family:'Panic Sans';color:rgb(195,89,0)" class=""><span style="color:#cf8724" class=""><br class=""></span></div></div></div><div class=""><br class=""></div><div class=""><div class="">Googling this issue, I find that it’s the subject of a lot of discussion. Evidently, simply setting the bit rate in the context is not sufficient — I can set <font face="Courier" class="">m_AVIMOV_BPS</font> to 400 million, but the bitrate used in encoding ends up being something like 176 Kbps (using the info inspector in one of any number of players/utilities). As well, visually I see significant undersampling artifacts. I assume the effective bitrate used is computed by ffmpeg or the encoder itself, based on some other (default) parameters. But in any case, my value is being ignored, making the output useless to me.</div><div class=""><br class=""></div><div class="">One forum I post I found ( <a href="http://libav-users.943685.n4.nabble.com/Setting-libx264-bitrate-via-API-td4655453.html" target="_blank" class="">http://libav-users.943685.n4.nabble.com/Setting-libx264-bitrate-via-API-td4655453.html</a> ) suggests that the reason the encoder (or ffmpeg itself?) is ignoring the bit rate is because of the use of “pts” and “dts” in the encoder and output stream writer. Specifically, the encoder’s input should use, say, integer frame numbers, while the stream writer should use values in its own time base: </div></div><div class=""><br class=""></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">My code was sending pictures into the encoder using a pts in the stream's </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">time_base of 1/90000 (e.g. 3003, 6006, 9009).  The solution was to first </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">rescale the AVFrame's pts from the stream's time_base to the codec time_base </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">to get a simple frame number (e.g. 1, 2, 3). </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Courier" class=""><br style="font-size:13px" class=""></font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">pic->pts = av_rescale_q(pic->pts, ost->time_base, enc->time_base); </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">avcodec_encode_video2(enc, &newpkt, pic, &got_packet_ptr); </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Courier" class=""><br style="font-size:13px" class=""></font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">Then when a packet is received from the encoder, you need to rescale pts and </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">dts back to the stream time_base. </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><font face="Courier" class=""><br style="font-size:13px" class=""></font></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">newpkt.pts = av_rescale_q(newpkt.pts, enc->time_base, ost->time_base); </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">newpkt.dts = av_rescale_q(newpkt.dts, enc->time_base, ost->time_base); </font></span></div></blockquote><blockquote style="margin:0 0 0 40px;border:none;padding:0px" class=""><div class=""><span style="font-size:13px;background-color:rgb(255,255,255)" class=""><font face="Courier" class="">av_interleaved_write_frame(out, &newpkt); </font></span></div></blockquote></blockquote><div class=""><br class=""></div><div class="">However, this is not working for me. I suspect it may be due to other differences between my code and theirs.. :-(</div><div class=""><br class=""></div><div class="">In any case, surely someone out there has the understanding (and code snippets?) of how to get the libx264 encoder to honor the specified bitrate? Any help/pointers/advice/code would be greatly appreciated!</div><div class=""><br class=""></div><div class="">Thanks!</div><div class=""><br class=""></div><div class=""><br class=""></div></div><br class="">_______________________________________________<br class="">
Libav-user mailing list<br class="">
<a href="mailto:Libav-user@ffmpeg.org" target="_blank" class="">Libav-user@ffmpeg.org</a><br class="">
<a href="http://ffmpeg.org/mailman/listinfo/libav-user" target="_blank" class="">http://ffmpeg.org/mailman/listinfo/libav-user</a><br class="">
<br class=""></blockquote></div><br class=""></div>
_______________________________________________<br class="">Libav-user mailing list<br class=""><a href="mailto:Libav-user@ffmpeg.org" target="_blank" class="">Libav-user@ffmpeg.org</a><br class=""><a href="http://ffmpeg.org/mailman/listinfo/libav-user" target="_blank" class="">http://ffmpeg.org/mailman/listinfo/libav-user</a><br class=""></div></blockquote></div><br class=""></div></div></div><br class="">_______________________________________________<br class="">
Libav-user mailing list<br class="">
<a href="mailto:Libav-user@ffmpeg.org" class="">Libav-user@ffmpeg.org</a><br class="">
<a href="http://ffmpeg.org/mailman/listinfo/libav-user" target="_blank" class="">http://ffmpeg.org/mailman/listinfo/libav-user</a><br class="">
<br class=""></blockquote></div><br class=""></div>
_______________________________________________<br class="">Libav-user mailing list<br class=""><a href="mailto:Libav-user@ffmpeg.org" class="">Libav-user@ffmpeg.org</a><br class="">http://ffmpeg.org/mailman/listinfo/libav-user<br class=""></div></blockquote></div><br class=""></div></body></html>