summaryrefslogtreecommitdiffstats
path: root/debian/transcode/transcode-1.1.7/export/divx4_vbr.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/transcode/transcode-1.1.7/export/divx4_vbr.c')
-rw-r--r--debian/transcode/transcode-1.1.7/export/divx4_vbr.c434
1 files changed, 434 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/export/divx4_vbr.c b/debian/transcode/transcode-1.1.7/export/divx4_vbr.c
new file mode 100644
index 00000000..94ca5c4d
--- /dev/null
+++ b/debian/transcode/transcode-1.1.7/export/divx4_vbr.c
@@ -0,0 +1,434 @@
+/*
+ * divx4_vbr.c
+ *
+ * Copyright (C) Thomas Oestreich - June 2001
+ *
+ * 2-pass code OpenDivX port:
+ * Copyright (C) 2001 Christoph Lampert <gruel@gmx.de>
+ *
+ * This file is part of transcode, a video stream processing tool
+ *
+ * transcode is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * transcode 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/**********************************************************
+ * Two-pass-code from OpenDivX *
+ * *
+ * Large parts of this code were taken from VbrControl() *
+ * from the OpenDivX project, (C) divxnetworks, *
+ * this code is published under DivX Open license, which *
+ * can be found... somewhere... oh, whatever... *
+ **********************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdint.h>
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#else
+# ifdef OS_DARWIN
+# include "libdldarwin/dlfcn.h"
+# endif
+#endif
+
+#include "transcode.h"
+#include "libtc/libtc.h"
+#include "vbr.h"
+
+/* Absolute maximum and minimum quantizers used in VBR modes */
+static const int min_quantizer=1;
+static const int max_quantizer=31;
+
+/* Limits on frame-level deviation of quantizer ( higher values
+ correspond to frames with more changes and vice versa ) */
+static const float min_quant_delta=-10.f;
+static const float max_quant_delta=5.f;
+/* Limits on stream-level deviation of quantizer ( used to make
+ overall bitrate of stream close to requested value ) */
+static const float min_rc_quant_delta=.6f;
+static const float max_rc_quant_delta=1.5f;
+
+typedef struct entry_s {
+/* max 28 bytes/frame or 5 Mb for 2-hour movie */
+ int quant;
+ int text_bits;
+ int motion_bits;
+ int total_bits;
+ float mult;
+ int is_key_frame;
+ int drop;
+} entry;
+
+int m_iCount;
+int m_iQuant;
+int m_iCrispness;
+short m_bDrop;
+float m_fQuant;
+
+int64_t m_lEncodedBits;
+int64_t m_lExpectedBits;
+
+FILE *m_pFile;
+
+entry vFrame;
+entry *m_vFrames;
+long lFrameStart;
+
+int iNumFrames;
+int dummy;
+
+void VbrControl_init_1pass_vbr(int quality, int crispness)
+{
+ m_fQuant = min_quantizer+((max_quantizer-min_quantizer)/6.)*(6-quality);
+ m_iCount = 0;
+ m_bDrop = TC_FALSE;
+ VbrControl_update_1pass_vbr();
+}
+
+int VbrControl_init_2pass_vbr_analysis(const char *filename, int quality)
+{
+ m_pFile = fopen(filename, "wb");
+ if (m_pFile == NULL) {
+ return -1;
+ }
+ m_iCount = 0;
+ m_bDrop = TC_FALSE;
+ fprintf(m_pFile, "##version 1\n");
+ fprintf(m_pFile, "quality %d\n", quality);
+ return 0;
+}
+
+int VbrControl_init_2pass_vbr_encoding(const char *filename, int bitrate,
+ double framerate, int crispness,
+ int quality)
+{
+ int i;
+
+ int64_t text_bits = 0;
+ int64_t total_bits = 0;
+ int64_t complexity = 0;
+ int64_t new_complexity = 0;
+ int64_t motion_bits = 0;
+ int64_t denominator = 0;
+ float qual_multiplier = 1.;
+ char head[20];
+
+ int64_t desired_bits;
+ int64_t non_text_bits;
+
+ float average_complexity;
+
+ m_pFile = fopen(filename, "rb");
+ if (m_pFile == NULL) {
+ return -1;
+ }
+ m_bDrop = TC_FALSE;
+ m_iCount = 0;
+
+ fread(head, 10, 1, m_pFile);
+ if (strncmp("##version ", head, 10) == 0) {
+ int version;
+ int iOldQual;
+ float old_qual = 0, new_qual = 0;
+
+ fscanf(m_pFile, "%d\n", &version);
+ fscanf(m_pFile, "quality %d\n", &iOldQual);
+ switch (iOldQual) {
+ case 5:
+ old_qual = 1.f;
+ break;
+ case 4:
+ old_qual = 1.1f;
+ break;
+ case 3:
+ old_qual = 1.25f;
+ break;
+ case 2:
+ old_qual = 1.4f;
+ break;
+ case 1:
+ old_qual = 2.f;
+ break;
+ }
+
+ switch (quality) {
+ case 5:
+ new_qual = 1.f;
+ break;
+ case 4:
+ new_qual = 1.1f;
+ break;
+ case 3:
+ new_qual = 1.25f;
+ break;
+ case 2:
+ new_qual = 1.4f;
+ break;
+ case 1:
+ new_qual = 2.f;
+ break;
+ }
+ qual_multiplier = new_qual/old_qual;
+ } else { /* strncmp("##version ", head, 10) != 0 */
+ fseek(m_pFile, 0, SEEK_SET);
+ }
+
+ lFrameStart = ftell(m_pFile); // save current position
+
+/* removed C++ dependencies, now read file twice :-( */
+
+ while (!feof(m_pFile)) {
+ fscanf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, "
+ "motion %d, total %d\n",
+ &iNumFrames, (int *) &(vFrame.is_key_frame),
+ &(vFrame.quant), &(vFrame.text_bits),
+ &(vFrame.motion_bits), &(vFrame.total_bits));
+
+ vFrame.total_bits += vFrame.text_bits*(qual_multiplier-1);
+ vFrame.text_bits *= qual_multiplier;
+ text_bits += (int64_t)vFrame.text_bits;
+ motion_bits += (int64_t)vFrame.motion_bits;
+ total_bits += (int64_t)vFrame.total_bits;
+ complexity += (int64_t)vFrame.text_bits*vFrame.quant;
+
+ }
+ iNumFrames++;
+ average_complexity = complexity/iNumFrames;
+
+ if (verbose & TC_DEBUG) {
+ tc_log_info(__FILE__, "frames %d, texture %lld, motion %lld, "
+ "total %lld, complexity %lld",
+ iNumFrames, (long long)text_bits, (long long)motion_bits,
+ (long long)total_bits, (long long)complexity);
+ }
+
+ m_vFrames = tc_malloc(iNumFrames*sizeof(entry));
+ if (!m_vFrames) {
+ return TC_EXPORT_ERROR;
+ }
+
+ fseek(m_pFile, lFrameStart, SEEK_SET); /* start again */
+
+ for (i = 0; i < iNumFrames; i++) {
+ fscanf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, "
+ "motion %d, total %d\n",
+ &dummy, (int *) &(m_vFrames[i].is_key_frame),
+ &(m_vFrames[i].quant), &(m_vFrames[i].text_bits),
+ &(m_vFrames[i].motion_bits), &(m_vFrames[i].total_bits));
+
+ m_vFrames[i].total_bits += m_vFrames[i].text_bits*(qual_multiplier-1);
+ m_vFrames[i].text_bits *= qual_multiplier;
+ }
+
+ if (m_pFile != NULL) {
+ fclose(m_pFile);
+ m_pFile=NULL;
+ }
+
+ desired_bits = (int64_t)bitrate*(int64_t)iNumFrames/framerate;
+ non_text_bits = total_bits-text_bits;
+
+ if (desired_bits <= non_text_bits) {
+ tc_log_warn(__FILE__, "Specified bitrate is too low for this clip.\n"
+ "Minimum possible bitrate for the clip is %.0f"
+ " kbps. Overriding user-specified value.\n",
+ (float)(non_text_bits*framerate/(int64_t)iNumFrames));
+
+ desired_bits=non_text_bits*3/2;
+ }
+
+ desired_bits -= non_text_bits;
+ /**
+ BRIEF EXPLANATION OF WHAT'S GOING ON HERE.
+ We assume that
+ text_bits=complexity / quantizer
+ total_bits-text_bits = const(complexity)
+ where 'complexity' is a characteristic of the frame
+ and does not depend much on quantizer dynamics.
+ Using this equation, we calculate 'average' quantizer
+ to be used for encoding ( 1st order effect ).
+ Having constant quantizer for the entire stream is not
+ very convenient - reconstruction errors are
+ more noticeable in low-motion scenes. To compensate
+ this effect, we multiply quantizer for each frame by
+ (complexity/average_complexity)^k,
+ ( k - parameter of adjustment ). k=0 means 'no compensation'
+ and k=1 is 'constant bitrate mode'. We choose something in
+ between, like 0.5 ( 2nd order effect ).
+ **/
+
+ average_complexity = complexity/iNumFrames;
+
+ for (i = 0; i < iNumFrames; i++) {
+ float mult;
+ if (m_vFrames[i].is_key_frame) {
+ if ((i+1<iNumFrames) && (m_vFrames[i+1].is_key_frame))
+ mult=1.25;
+ else
+ mult=.75;
+ } else {
+ mult = m_vFrames[i].text_bits*m_vFrames[i].quant;
+ mult = (float)sqrt(mult/average_complexity);
+
+ if (mult<0.5)
+ mult=0.5;
+ if (mult>1.5)
+ mult=1.5;
+ }
+
+ m_vFrames[i].mult = mult;
+ m_vFrames[i].drop = TC_FALSE;
+ new_complexity += m_vFrames[i].text_bits*m_vFrames[i].quant;
+
+ denominator += desired_bits*m_vFrames[i].mult/iNumFrames;
+ }
+
+ m_fQuant = ((double)new_complexity)/(double)denominator;
+
+ if (m_fQuant < min_quantizer)
+ m_fQuant=min_quantizer;
+ if (m_fQuant > max_quantizer)
+ m_fQuant=max_quantizer;
+ m_pFile = fopen("analyse.log", "wb");
+ if (m_pFile) {
+ fprintf(m_pFile, "Total frames: %d Avg quantizer: %f\n",
+ iNumFrames, m_fQuant);
+ fprintf(m_pFile, "Expecting %12lld bits\n",
+ (long long)desired_bits+(long long)non_text_bits);
+ fflush(m_pFile);
+ }
+ VbrControl_set_quant(m_fQuant*m_vFrames[0].mult);
+ m_lEncodedBits = m_lExpectedBits=0;
+ return 0;
+}
+
+int VbrControl_get_intra()
+{
+ return m_vFrames[m_iCount].is_key_frame;
+}
+
+short VbrControl_get_drop()
+{
+ return m_bDrop;
+}
+
+int VbrControl_get_quant()
+{
+ return m_iQuant;
+}
+
+void VbrControl_set_quant(float quant)
+{
+ m_iQuant=quant;
+ if((rand() % 10) < ((quant-m_iQuant) * 10))
+ m_iQuant++;
+ if(m_iQuant<min_quantizer)
+ m_iQuant=min_quantizer;
+ if(m_iQuant>max_quantizer)
+ m_iQuant=max_quantizer;
+}
+
+void VbrControl_update_1pass_vbr()
+{
+ VbrControl_set_quant(m_fQuant);
+ m_iCount++;
+}
+
+void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits,
+ int texture_bits, int total_bits,
+ int quant)
+{
+ if(m_pFile != NULL) {
+ fprintf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, "
+ "motion %d, total %d\n",
+ m_iCount, is_key_frame, quant, texture_bits, motion_bits,
+ total_bits);
+ m_iCount++;
+ }
+}
+
+void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits,
+ int total_bits)
+{
+ double q;
+ double dq;
+
+ if(m_iCount >= iNumFrames) {
+ return;
+ }
+
+ m_lExpectedBits += (m_vFrames[m_iCount].total_bits - m_vFrames[m_iCount].text_bits)
+ + m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant/m_fQuant;
+ m_lEncodedBits += (int64_t)total_bits;
+
+ if (m_pFile != NULL) {
+ fprintf(m_pFile, "Frame %d: PRESENT, complexity %d, "
+ "quant multiplier %f, texture %d, total %d ",
+ m_iCount, m_vFrames[m_iCount].text_bits * m_vFrames[m_iCount].quant,
+ m_vFrames[m_iCount].mult, texture_bits, total_bits);
+ }
+ m_iCount++;
+
+ q = m_fQuant * m_vFrames[m_iCount].mult;
+ if (q < m_fQuant + min_quant_delta) {
+ q = m_fQuant+min_quant_delta;
+ }
+ if (q > m_fQuant + max_quant_delta) {
+ q = m_fQuant+max_quant_delta;
+ }
+
+ dq = (double)m_lEncodedBits/(double)m_lExpectedBits;
+ dq *= dq;
+ if (dq < min_rc_quant_delta) {
+ dq = min_rc_quant_delta;
+ }
+ if (dq > max_rc_quant_delta) {
+ dq = max_rc_quant_delta;
+ }
+ if (m_iCount < 20) { // no framerate corrections in first frames
+ dq = 1;
+ }
+ if (m_pFile) {
+ fprintf(m_pFile, "Progress: expected %12lld, achieved %12lld, dq %f",
+ (long long)m_lExpectedBits,
+ (long long)m_lEncodedBits,
+ dq);
+ }
+ q *= dq;
+ VbrControl_set_quant(q);
+ if (m_pFile != NULL) {
+ fprintf(m_pFile, ", new quant %d\n", m_iQuant);
+ }
+}
+
+void VbrControl_close()
+{
+ if (m_pFile != NULL) {
+ fclose(m_pFile);
+ m_pFile = NULL;
+ }
+ free(m_vFrames);
+}