📄 mpegvideo.c
字号:
/*
* The simplest mpeg encoder (well, it was the simplest!)
* Copyright (c) 2000,2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
* 4MV & hq & B-frame encoding stuff by Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file mpegvideo.c
* The simplest mpeg encoder (well, it was the simplest!).
*/
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "mem.h"
#include "eval.h"
#include "common.h"
#include "bswap.h"
#include "intreadwrite.h"
#include "rational.h"
#include "log.h"
#include "avutil.h"
#include "ratecontrol.h"
#include "avcodec.h"
#include "parser.h"
#include "bitstream.h"
#include "rl.h"
#include "dsputil.h"#include "mpegvideo.h"
#include "msmpeg4.h"
#include "define.h"
#include "internal.h"
#include "mpegvideo_common.h"
//#undef NDEBUG
//#include <assert.h>
static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_h263_intra_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
static void dct_unquantize_h263_inter_c(MpegEncContext *s,
DCTELEM *block, int n, int qscale);
extern int XVMC_field_start(MpegEncContext*s, AVCodecContext *avctx);
extern void XVMC_field_end(MpegEncContext *s);
extern void XVMC_decode_mb(MpegEncContext *s);
static const uint8_t ff_default_chroma_qscale_table[32]={
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
};
const uint8_t ff_mpeg1_dc_scale_table[128]={
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
const uint8_t *ff_find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state){
int i;
assert(p<=end);
if(p>=end)
return end;
for(i=0; i<3; i++){
uint32_t tmp= *state << 8;
*state= tmp + *(p++);
if(tmp == 0x100 || p==end)
return p;
}
while(p<end){
if (p[-1] > 1 ) p+= 3;
else if(p[-2] ) p+= 2;
else if(p[-3]|(p[-1]-1)) p++;
else{
p++;
break;
}
}
p= FFMIN(p, end)-4;
*state= AV_RB32(p);
return p+4;
}
/* init common dct for both encoder and decoder */
int ff_dct_common_init(MpegEncContext *s)
{
s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c;
s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c;
s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c;
s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c;
s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c;
if(s->flags & CODEC_FLAG_BITEXACT)
s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact;
s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c;
#if defined(HAVE_MMX)
MPV_common_init_mmx(s);
#elif defined(ARCH_ALPHA)
MPV_common_init_axp(s);
#elif defined(CONFIG_MLIB)
MPV_common_init_mlib(s);
#elif defined(HAVE_MMI)
MPV_common_init_mmi(s);
#elif defined(ARCH_ARMV4L)
MPV_common_init_armv4l(s);
#elif defined(HAVE_ALTIVEC)
MPV_common_init_altivec(s);
#elif defined(ARCH_BFIN)
MPV_common_init_bfin(s);
#endif
/* load & permutate scantables
note: only wmv uses different ones
*/
if(s->alternate_scan){
ff_init_scantable(s->dsp.idct_permutation, &s->inter_scantable , ff_alternate_vertical_scan);
ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable , ff_alternate_vertical_scan);
}else{
ff_init_scantable(s->dsp.idct_permutation, &s->inter_scantable , ff_zigzag_direct);
ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable , ff_zigzag_direct);
}
ff_init_scantable(s->dsp.idct_permutation, &s->intra_h_scantable, ff_alternate_horizontal_scan);
ff_init_scantable(s->dsp.idct_permutation, &s->intra_v_scantable, ff_alternate_vertical_scan);
return 0;
}
void copy_picture(Picture *dst, Picture *src){
*dst = *src;
dst->type= FF_BUFFER_TYPE_COPY;
}
/**
* allocates a Picture
* The pixels are allocated/set by calling get_buffer() if shared=0
*/
int alloc_picture(MpegEncContext *s, Picture *pic, int shared){
const int big_mb_num= s->mb_stride*(s->mb_height+1) + 1; //the +1 is needed so memset(,,stride*height) does not sig11
const int mb_array_size= s->mb_stride*s->mb_height;
const int b8_array_size= s->b8_stride*s->mb_height*2;
const int b4_array_size= s->b4_stride*s->mb_height*4;
int i;
int r= -1;
if(shared){
assert(pic->data[0]);
assert(pic->type == 0 || pic->type == FF_BUFFER_TYPE_SHARED);
pic->type= FF_BUFFER_TYPE_SHARED;
}else{
assert(!pic->data[0]);
r= s->avctx->get_buffer(s->avctx, (AVFrame*)pic);
if(r<0 || !pic->age || !pic->type || !pic->data[0]){
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed (%d %d %d %p)\n", r, pic->age, pic->type, pic->data[0]);
return -1;
}
if(s->linesize && (s->linesize != pic->linesize[0] || s->uvlinesize != pic->linesize[1])){
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed (stride changed)\n");
s->avctx->release_buffer(s->avctx, (AVFrame*)pic);
return -1;
}
if(pic->linesize[1] != pic->linesize[2]){
av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed (uv stride mismatch)\n");
s->avctx->release_buffer(s->avctx, (AVFrame*)pic);
return -1;
}
s->linesize = pic->linesize[0];
s->uvlinesize= pic->linesize[1];
}
if(pic->qscale_table==NULL){
if (s->encoding) {
CHECKED_ALLOCZ(pic->mb_var , mb_array_size * sizeof(int16_t))
CHECKED_ALLOCZ(pic->mc_mb_var, mb_array_size * sizeof(int16_t))
CHECKED_ALLOCZ(pic->mb_mean , mb_array_size * sizeof(int8_t))
}
CHECKED_ALLOCZ(pic->mbskip_table , mb_array_size * sizeof(uint8_t)+2) //the +2 is for the slice end check
CHECKED_ALLOCZ(pic->qscale_table , mb_array_size * sizeof(uint8_t))
CHECKED_ALLOCZ(pic->mb_type_base , (big_mb_num + s->mb_stride) * sizeof(uint32_t))
pic->mb_type= pic->mb_type_base + 2*s->mb_stride+1;
if(s->out_format == FMT_H264){
for(i=0; i<2; i++){
CHECKED_ALLOCZ(pic->motion_val_base[i], 2 * (b4_array_size+4) * sizeof(int16_t))
pic->motion_val[i]= pic->motion_val_base[i]+4;
CHECKED_ALLOCZ(pic->ref_index[i], b8_array_size * sizeof(uint8_t))
}
pic->motion_subsample_log2= 2;
}else if(s->out_format == FMT_H263 || s->encoding || (s->avctx->debug&FF_DEBUG_MV) || (s->avctx->debug_mv)){
for(i=0; i<2; i++){
CHECKED_ALLOCZ(pic->motion_val_base[i], 2 * (b8_array_size+4) * sizeof(int16_t))
pic->motion_val[i]= pic->motion_val_base[i]+4;
CHECKED_ALLOCZ(pic->ref_index[i], b8_array_size * sizeof(uint8_t))
}
pic->motion_subsample_log2= 3;
}
if(s->avctx->debug&FF_DEBUG_DCT_COEFF) {
CHECKED_ALLOCZ(pic->dct_coeff, 64 * mb_array_size * sizeof(DCTELEM)*6)
}
pic->qstride= s->mb_stride;
CHECKED_ALLOCZ(pic->pan_scan , 1 * sizeof(AVPanScan))
}
/* It might be nicer if the application would keep track of these
* but it would require an API change. */
memmove(s->prev_pict_types+1, s->prev_pict_types, PREV_PICT_TYPES_BUFFER_SIZE-1);
s->prev_pict_types[0]= s->dropable ? FF_B_TYPE : s->pict_type;
if(pic->age < PREV_PICT_TYPES_BUFFER_SIZE && s->prev_pict_types[pic->age] == FF_B_TYPE)
pic->age= INT_MAX; // Skipped MBs in B-frames are quite rare in MPEG-1/2 and it is a bit tricky to skip them anyway.
return 0;
fail: //for the CHECKED_ALLOCZ macro
if(r>=0)
s->avctx->release_buffer(s->avctx, (AVFrame*)pic);
return -1;
}
/**
* deallocates a picture
*/
static void free_picture(MpegEncContext *s, Picture *pic){
int i;
if(pic->data[0] && pic->type!=FF_BUFFER_TYPE_SHARED){
s->avctx->release_buffer(s->avctx, (AVFrame*)pic);
}
av_freep(&pic->mb_var);
av_freep(&pic->mc_mb_var);
av_freep(&pic->mb_mean);
av_freep(&pic->mbskip_table);
av_freep(&pic->qscale_table);
av_freep(&pic->mb_type_base);
av_freep(&pic->dct_coeff);
av_freep(&pic->pan_scan);
pic->mb_type= NULL;
for(i=0; i<2; i++){
av_freep(&pic->motion_val_base[i]);
av_freep(&pic->ref_index[i]);
}
if(pic->type == FF_BUFFER_TYPE_SHARED){
for(i=0; i<4; i++){
pic->base[i]=
pic->data[i]= NULL;
}
pic->type= 0;
}
}
static int init_duplicate_context(MpegEncContext *s, MpegEncContext *base){
int i;
// edge emu needs blocksize + filter length - 1 (=17x17 for halfpel / 21x21 for h264)
CHECKED_ALLOCZ(s->allocated_edge_emu_buffer, (s->width+64)*2*21*2); //(width + edge + align)*interlaced*MBsize*tolerance
s->edge_emu_buffer= s->allocated_edge_emu_buffer + (s->width+64)*2*21;
//FIXME should be linesize instead of s->width*2 but that is not known before get_buffer()
CHECKED_ALLOCZ(s->me.scratchpad, (s->width+64)*4*16*2*sizeof(uint8_t))
s->rd_scratchpad= s->me.scratchpad;
s->b_scratchpad= s->me.scratchpad;
s->obmc_scratchpad= s->me.scratchpad + 16;
if (s->encoding) {
CHECKED_ALLOCZ(s->me.map , ME_MAP_SIZE*sizeof(uint32_t))
CHECKED_ALLOCZ(s->me.score_map, ME_MAP_SIZE*sizeof(uint32_t))
if(s->avctx->noise_reduction){
CHECKED_ALLOCZ(s->dct_error_sum, 2 * 64 * sizeof(int))
}
}
CHECKED_ALLOCZ(s->blocks, 64*12*2 * sizeof(DCTELEM))
s->block= s->blocks[0];
for(i=0;i<12;i++){
s->pblocks[i] = (short *)(&s->block[i]);
}
return 0;
fail:
return -1; //free() through MPV_common_end()
}
static void free_duplicate_context(MpegEncContext *s){
if(s==NULL) return;
av_freep(&s->allocated_edge_emu_buffer); s->edge_emu_buffer= NULL;
av_freep(&s->me.scratchpad);
s->rd_scratchpad=
s->b_scratchpad=
s->obmc_scratchpad= NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -