<div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 27, 2024 at 3:35 PM Anusuya Kumarasamy <<a href="mailto:anusuya.kumarasamy@multicorewareinc.com">anusuya.kumarasamy@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From acb4ab5a4f14b7a88ccdf3bdc4b01ddf68fcec29 Mon Sep 17 00:00:00 2001<br>From: Hazarath Kumar M <<a href="mailto:hazarathkumar@multicorewareinc.com" target="_blank">hazarathkumar@multicorewareinc.com</a>><br>Date: Wed, 25 Sep 2024 14:35:27 +0530<br>Subject: [PATCH 4/5] Add Aom film grain characteristics as SEI message to the<br> bitstream<br><br>---<br> doc/reST/cli.rst | 4 +<br> source/common/param.cpp | 7 ++<br> source/encoder/encoder.cpp | 11 +++<br> source/encoder/encoder.h | 2 +<br> source/encoder/frameencoder.cpp | 92 ++++++++++++++++++++++<br> source/encoder/frameencoder.h | 31 ++++++++<br> source/encoder/sei.h | 131 ++++++++++++++++++++++++++++++++<br> source/x265.h | 3 +<br> source/x265cli.cpp | 1 +<br> source/x265cli.h | 1 +<br> 10 files changed, 283 insertions(+)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 95cb37f20..a4907f7d2 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2702,6 +2702,10 @@ Bitstream options<br> <br> Refers to the film grain model characteristics for signal enhancement information transmission.<br> <br>+.. option:: --aom-film-grain <filename><br>+<br>+ Refers to the AOM film grain model characteristics<br>+<br> **CLI_ONLY**<br> <br> DCT Approximations<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index d08bb604e..ceef42589 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -402,6 +402,7 @@ void x265_param_default(x265_param* param)<br> #endif<br> /* Film grain characteristics model filename */<br> param->filmGrain = NULL;<br>+ param->aomFilmGrain = NULL;<br> param->bEnableSBRC = 0;<br> <br> /* Multi-View Encoding*/<br>@@ -1455,6 +1456,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br> OPT("eos") p->bEnableEndOfSequence = atobool(value);<br> /* Film grain characterstics model filename */<br> OPT("film-grain") p->filmGrain = (char* )value;<br>+ OPT("aom-film-grain") p->aomFilmGrain = (char*)value;<br> OPT("mcstf") p->bEnableTemporalFilter = atobool(value);<br> OPT("sbrc") p->bEnableSBRC = atobool(value);<br> #if ENABLE_ALPHA<br>@@ -2403,6 +2405,8 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br> BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");<br> if (p->filmGrain)<br> s += sprintf(s, " film-grain=%s", p->filmGrain); // Film grain characteristics model filename<br>+ if (p->aomFilmGrain)<br>+ s += sprintf(s, " aom-film-grain=%s", p->aomFilmGrain);<br> BOOL(p->bEnableTemporalFilter, "mcstf");<br> #if ENABLE_ALPHA<br> BOOL(p->bEnableAlpha, "alpha");<br>@@ -2956,6 +2960,9 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> /* Film grain */<br> if (src->filmGrain)<br> dst->filmGrain = src->filmGrain;<br>+ /* Aom Film grain*/<br>+ if (src->aomFilmGrain)<br>+ dst->aomFilmGrain = src->aomFilmGrain;<br> dst->bEnableSBRC = src->bEnableSBRC;<br> }<br> <br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 13b98e986..c78413bfb 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -142,6 +142,7 @@ Encoder::Encoder()<br> m_analysisFileIn = NULL;<br> m_analysisFileOut = NULL;<br> m_filmGrainIn = NULL;<br>+ m_aomFilmGrainIn = NULL;<br> m_naluFile = NULL;<br> m_offsetEmergency = NULL;<br> m_iFrameNum = 0;<br>@@ -533,6 +534,14 @@ void Encoder::create()<br> x265_log_file(NULL, X265_LOG_ERROR, "Failed to open film grain characteristics binary file %s\n", m_param->filmGrain);<br> }<br> }<br>+ if (m_param->aomFilmGrain)<br>+ {<br>+ m_aomFilmGrainIn = x265_fopen(m_param->aomFilmGrain, "rb");<br>+ if (!m_aomFilmGrainIn)<br>+ {<br>+ x265_log_file(NULL, X265_LOG_ERROR, "Failed to open Aom film grain characteristics binary file %s\n", m_param->aomFilmGrain);<br>+ }<br>+ }<br> <br> m_bZeroLatency = !m_param->bframes && !m_param->lookaheadDepth && m_param->frameNumThreads == 1 && m_param->maxSlices == 1;<br> m_aborted |= parseLambdaFile(m_param);<br>@@ -973,6 +982,8 @@ void Encoder::destroy()<br> fclose(m_naluFile);<br> if (m_filmGrainIn)<br> x265_fclose(m_filmGrainIn);<br>+ if (m_aomFilmGrainIn)<br>+ x265_fclose(m_aomFilmGrainIn);<br> <br> #ifdef SVT_HEVC<br> X265_FREE(m_svtAppData);<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index e5020c1dc..4b72f8bf9 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -285,6 +285,8 @@ public:<br> ThreadSafeInteger* zoneWriteCount;<br> /* Film grain model file */<br> FILE* m_filmGrainIn;<br>+ /* Aom film grain model file*/<br>+ FILE* m_aomFilmGrainIn;<br> OrigPicBuffer* m_origPicBuffer;<br> <br> Encoder();<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index deb478a0f..e21dbfa85 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -872,6 +872,14 @@ void FrameEncoder::compressFrame(int layer)<br> readModel(&m_filmGrain, this->m_top->m_filmGrainIn);<br> m_filmGrain.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal, layer);<br> }<br>+ /* Write Aom film grain characteristics if present */<br>+ if (this->m_top->m_aomFilmGrainIn)<br>+ {<br>+ AomFilmGrainCharacteristics m_aomFilmGrain;<br>+ /* Read the Film grain model file */<br>+ readAomModel(&m_aomFilmGrain, this->m_top->m_aomFilmGrainIn);<br>+ m_aomFilmGrain.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal);<br>+ }<br> /* Write user SEI */<br> for (int i = 0; i < m_frame[layer]->m_userSEI.numPayloads; i++)<br> {<br>@@ -2335,6 +2343,90 @@ void FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgr<br> }<br> }<br> }<br>+<br>+void FrameEncoder::readAomModel(AomFilmGrainCharacteristics* m_aomFilmGrain, FILE* Aomfilmgrain)<br>+{<br>+ char const* errorMessage = "Error reading Aom FilmGrain characteristics\n";<br>+ AomFilmGrain m_afg;<br>+ x265_fread((char*)&m_aomFilmGrain->m_apply_grain, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_grain_seed, sizeof(uint16_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_update_grain, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_num_y_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ if (m_aomFilmGrain->m_num_y_points)<br>+ {<br>+ for (int i = 0; i < m_aomFilmGrain->m_num_y_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_scaling_points_y[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ }<br>+ x265_fread((char*)&m_aomFilmGrain->m_num_cb_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ if (m_aomFilmGrain->m_num_cb_points)<br>+ {<br>+ for (int i = 0; i < m_aomFilmGrain->m_num_cb_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_scaling_points_cb[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ }<br>+ x265_fread((char*)&m_aomFilmGrain->m_num_cr_points, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ if (m_aomFilmGrain->m_num_cr_points)<br>+ {<br>+ for (int i = 0; i < m_aomFilmGrain->m_num_cr_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_scaling_points_cr[i][j], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ }<br>+ x265_fread((char*)&m_aomFilmGrain->m_scaling_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_lag, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ if (m_aomFilmGrain->m_num_y_points)<br>+ {<br>+<br>+ for (int i = 0; i < 24; i++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_y[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ if (m_aomFilmGrain->m_num_cb_points || m_afg.m_chroma_scaling_from_luma)<br>+ {<br>+ for (int i = 0; i < 25; i++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cb[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ if (m_aomFilmGrain->m_num_cr_points || m_afg.m_chroma_scaling_from_luma)<br>+ {<br>+<br>+ for (int i = 0; i < 25; i++)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeffs_cr[i], sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ }<br>+ x265_fread((char*)&m_aomFilmGrain->m_ar_coeff_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_grain_scale_shift, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ if (m_aomFilmGrain->m_num_cb_points)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_cb_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_cb_luma_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_cb_offset, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ if (m_aomFilmGrain->m_num_cr_points)<br>+ {<br>+ x265_fread((char*)&m_aomFilmGrain->m_cr_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_cr_luma_mult, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_cr_offset, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ }<br>+ x265_fread((char*)&m_aomFilmGrain->m_overlap_flag, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+ x265_fread((char*)&m_aomFilmGrain->m_clip_to_restricted_range, sizeof(int32_t), 1, Aomfilmgrain, errorMessage);<br>+}<br>+<br> #if ENABLE_LIBVMAF<br> void FrameEncoder::vmafFrameLevelScore()<br> {<br>diff --git a/source/encoder/frameencoder.h b/source/encoder/frameencoder.h<br>index ebc6e57c5..21d05c2f2 100644<br>--- a/source/encoder/frameencoder.h<br>+++ b/source/encoder/frameencoder.h<br>@@ -142,6 +142,36 @@ struct FGPresent<br> bool m_presentFlag[3];<br> };<br> <br>+struct AomFilmGrain<br>+{<br>+ int32_t m_apply_grain;<br>+ int32_t m_update_grain;<br>+ int32_t m_scaling_points_y[14][2];<br>+ int32_t m_num_y_points;<br>+ int32_t m_scaling_points_cb[10][2];<br>+ int32_t m_num_cb_points;<br>+ int32_t m_scaling_points_cr[10][2];<br>+ int32_t m_num_cr_points;<br>+ int32_t m_scaling_shift;<br>+ int32_t m_ar_coeff_lag;<br>+ int32_t m_ar_coeffs_y[24];<br>+ int32_t m_ar_coeffs_cb[25];<br>+ int32_t m_ar_coeffs_cr[25];<br>+ int32_t m_ar_coeff_shift;<br>+ int32_t m_cb_mult;<br>+ int32_t m_cb_luma_mult;<br>+ int32_t m_cb_offset;<br>+ int32_t m_cr_mult;<br>+ int32_t m_cr_luma_mult;<br>+ int32_t m_cr_offset;<br>+ int32_t m_overlap_flag;<br>+ int32_t m_clip_to_restricted_range;<br>+ int32_t m_bitDepth;<br>+ int32_t m_chroma_scaling_from_luma;<br>+ int32_t m_grain_scale_shift;<br>+ uint16_t m_grain_seed;<br>+};<br>+<br> // Manages the wave-front processing of a single encoding frame<br> class FrameEncoder : public WaveFront, public Thread<br> {<br>@@ -287,6 +317,7 @@ protected:<br> void computeAvgTrainingData(int layer);<br> void collectDynDataRow(CUData& ctu, FrameStats* rowStats); <br> void readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgrain);<br>+ void readAomModel(AomFilmGrainCharacteristics* m_aomFilmGrain, FILE* Aomfilmgrain);<br> };<br> }<br> <br>diff --git a/source/encoder/sei.h b/source/encoder/sei.h<br>index e357a1bf5..1fa4dc69b 100644<br>--- a/source/encoder/sei.h<br>+++ b/source/encoder/sei.h<br>@@ -168,6 +168,137 @@ class FilmGrainCharacteristics : public SEI<br> }<br> };<br> <br>+class AomFilmGrainCharacteristics : public SEI {<br>+<br>+public:<br>+<br>+ AomFilmGrainCharacteristics()<br>+ {<br>+ m_payloadType = USER_DATA_REGISTERED_ITU_T_T35;<br>+ m_payloadSize = 0;<br>+ }<br>+<br>+ int32_t m_apply_grain;<br>+ int32_t m_update_grain;<br>+ int32_t m_scaling_points_y[14][2];<br>+ int32_t m_num_y_points;<br>+ int32_t m_scaling_points_cb[10][2];<br>+ int32_t m_num_cb_points;<br>+ int32_t m_scaling_points_cr[10][2];<br>+ int32_t m_num_cr_points;<br>+ int32_t m_scaling_shift;<br>+ int32_t m_ar_coeff_lag;<br>+ int32_t m_ar_coeffs_y[24];<br>+ int32_t m_ar_coeffs_cb[25];<br>+ int32_t m_ar_coeffs_cr[25];<br>+ int32_t m_ar_coeff_shift;<br>+ int32_t m_cb_mult;<br>+ int32_t m_cb_luma_mult;<br>+ int32_t m_cb_offset;<br>+ int32_t m_cr_mult;<br>+ int32_t m_cr_luma_mult;<br>+ int32_t m_cr_offset;<br>+ int32_t m_overlap_flag;<br>+ int32_t m_clip_to_restricted_range;<br>+ int32_t m_bitDepth;<br>+ int32_t m_chroma_scaling_from_luma;<br>+ int32_t m_grain_scale_shift;<br>+ uint16_t m_grain_seed;<br>+<br>+ void writeSEI(const SPS&)<br>+ {<br>+ WRITE_CODE(0x26, 8, "country_code");<br>+ WRITE_CODE(0x5890, 16, "provider_code");<br>+ WRITE_CODE(0x0001, 16, "provider_oriented_code");<br>+ WRITE_FLAG(m_apply_grain, "afgs1_enable_flag");<br>+ WRITE_CODE(m_grain_seed, 16, "grain_seed");<br>+ WRITE_CODE(0, 3, "film_grain_param_set_idx");<br>+ WRITE_CODE(m_update_grain, 1, "update_grain");<br>+ WRITE_CODE(m_num_y_points, 4, "num_y_points");<br>+ if (m_num_y_points)<br>+ {<br>+ for (int i = 0; i < m_num_y_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ WRITE_CODE(m_scaling_points_y[i][j], 8, "scaling_points_y[i][j]");<br>+ }<br>+ }<br>+ }<br>+ WRITE_FLAG(m_num_cb_points == 0 && m_num_cr_points == 0, "luma_only_flag");<br>+ WRITE_FLAG(0, "chroma_scaling_from_luma");<br>+ WRITE_CODE(m_num_cb_points, 4, "num_cb_points");<br>+ if (m_num_cb_points)<br>+ {<br>+ for (int i = 0; i < m_num_cb_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ WRITE_CODE(m_scaling_points_cb[i][j], 8, "scaling_points_cb[i][j]");<br>+ }<br>+ }<br>+ }<br>+ WRITE_CODE(m_num_cr_points, 4, "num_cr_points");<br>+ if (m_num_cr_points)<br>+ {<br>+ for (int i = 0; i < m_num_cr_points; i++)<br>+ {<br>+ for (int j = 0; j < 2; j++)<br>+ {<br>+ WRITE_CODE(m_scaling_points_cr[i][j], 8, "scaling_points_cr[i][j]");<br>+ }<br>+ }<br>+ }<br>+ WRITE_CODE(m_scaling_shift - 8, 2, "scaling_shift");<br>+ WRITE_CODE(m_ar_coeff_lag, 2, "ar_coeff_lag");<br>+ if (m_num_y_points)<br>+ {<br>+ for (int i = 0; i < 24; i++)<br>+ {<br>+ WRITE_CODE(m_ar_coeffs_y[i] + 128, 8, "ar_coeff_y[i]");<br>+ }<br>+ }<br>+ if (m_num_cb_points || m_chroma_scaling_from_luma)<br>+ {<br>+ for (int i = 0; i < 25; i++)<br>+ {<br>+ WRITE_CODE(m_ar_coeffs_cb[i] + 128, 8, "ar_coeff_cb[i]");<br>+ }<br>+ }<br>+ if (m_num_cr_points || m_chroma_scaling_from_luma)<br>+ {<br>+ for (int i = 0; i < 25; i++)<br>+ {<br>+ WRITE_CODE(m_ar_coeffs_cr[i] + 128, 8, "ar_coeff_cr[i]");<br>+ }<br>+ }<br>+ WRITE_CODE(m_ar_coeff_shift - 6, 2, "ar_coeff_shift");<br>+ WRITE_CODE(m_grain_scale_shift, 2, "grain_scale_shift");<br>+ if (m_num_cb_points)<br>+ {<br>+ WRITE_CODE(m_cb_mult, 8, "cb_mult");<br>+ WRITE_CODE(m_cb_luma_mult, 8, "cb_luma_mult");<br>+ WRITE_CODE(m_cb_offset, 9, "cb_offset");<br>+ }<br>+ if (m_num_cr_points)<br>+ {<br>+ WRITE_CODE(m_cr_mult, 8, "cr_mult");<br>+ WRITE_CODE(m_cr_luma_mult, 8, "cr_luma_mult");<br>+ WRITE_CODE(m_cr_offset, 9, "cr_offset");<br>+ }<br>+ WRITE_FLAG(m_overlap_flag, "overlap_flag");<br>+ WRITE_FLAG(m_clip_to_restricted_range, "clip_to_restricted_range");<br>+ if (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)<br>+ {<br>+ WRITE_FLAG(1, "payload_bit_equal_to_one");<br>+ while (m_bitIf->getNumberOfWrittenBits() % X265_BYTE != 0)<br>+ {<br>+ WRITE_FLAG(0, "payload_bit_equal_to_zero");<br>+ }<br>+ }<br>+ }<br>+};<br>+<br> static const uint32_t ISO_IEC_11578_LEN = 16;<br> <br> class SEIuserDataUnregistered : public SEI<br>diff --git a/source/x265.h b/source/x265.h<br>index 532d01b22..54e699317 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -2307,6 +2307,9 @@ typedef struct x265_param<br> /* Film Grain Characteristic file */<br> char* filmGrain;<br> <br>+ /* Aom Film Grain Characteristic file */<br>+ char* aomFilmGrain;<br>+<br> /*Motion compensated temporal filter*/<br> int bEnableTemporalFilter;<br> double temporalFilterStrength;<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index ca7d9c973..b9ce96f19 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -408,6 +408,7 @@ namespace X265_NS {<br> H1(" 4 - encoder abort\n");<br> H0("\nSEI Message Options\n");<br> H0(" --film-grain <filename> File containing Film Grain Characteristics to be written as a SEI Message\n");<br>+ H0(" --aom-film-grain <filename> File containing Aom Film Grain Characteristics to be written as a SEI Message\n");<br> <br> #undef OPT<br> #undef H0<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 2ec48352d..3df0fa7a6 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -395,6 +395,7 @@ static const struct option long_options[] =<br> { "max-vbv-fullness", required_argument, NULL, 0 },<br> { "scenecut-qp-config", required_argument, NULL, 0 },<br> { "film-grain", required_argument, NULL, 0 },<br>+ { "aom-film-grain", required_argument, NULL, 0 },<br> { 0, 0, 0, 0 },<br> { 0, 0, 0, 0 },<br> { 0, 0, 0, 0 },<br>-- <br>2.36.0.windows.1<br><br></div>
</blockquote></div>