Hello,
I am working on video steganography in collaboration with northumbria
university. I am working with the H.264 standard. I made a program to
read and store the information about the macroblock partition and the
motion vector values, and to change the motion vectors in an AVFrame
structure. I am now trying to encode the video (with
"avcodec_encode_video2") with the macroblock partition and the motion
vectors stored in the AVFrame (instead of re-estimate these
parameters). I tryed to fix the "me_method" to ME_X1 (6) but it is not
sufficient. How to generate the bitstream (AVPacket) without estimate
the MB partition and the MV values?
Please find attached my program.
Nb : the function which write the video, "MV_ReadWrite", begin line
626, the codec information are set line 687, and the encoding loop
begin line 767.
Best regards,
Yves MICHELS.
// to compile
// gcc -std=c99 -o MV_ReadWrite -I/usr/include MV_ReadWrite.c -lavformat -lavcodec -lavutil -lz -lm
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <malloc.h>
#define IS_INTERLACED(a) ((a)&MB_TYPE_INTERLACED)
#define IS_16X16(a) ((a)&MB_TYPE_16x16)
#define IS_16X8(a) ((a)&MB_TYPE_16x8)
#define IS_8X16(a) ((a)&MB_TYPE_8x16)
#define IS_8X8(a) ((a)&MB_TYPE_8x8)
#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0|MB_TYPE_P1L0)<<(2*(list))))
#define FF_I_TYPE AV_PICTURE_TYPE_I ///< Intra
#define FF_P_TYPE AV_PICTURE_TYPE_P ///< Predicted
#define FF_B_TYPE AV_PICTURE_TYPE_B ///< Bi-dir predicted
#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
int count = 0;
double sum = 0;
double h;
double w;
int ***new_3D_int(int idim, int jdim, int kdim)
{
int ***matrice ;
int i ;
int j ;
matrice = (int***)malloc(idim*sizeof(int**));
for(i=0;i<idim;i++)
{
matrice[i] = (int**)malloc(jdim*sizeof(int*));
for(j=0;j<jdim;j++)
{
matrice[i][j] = (int*)malloc(kdim*sizeof(int));
}
}
return matrice;
}
void del_3D_int(int ***matrice, int idim, int jdim)
{
int i ;
int j ;
for(i=0;i<idim;i++)
{
for(j=0;j<jdim;j++)
{
free(matrice[i][j]);
}
free(matrice[i]);
}
free(matrice);
}
int ****new_4D_int(int idim, int jdim, int kdim, int ldim)
{
int ****matrice ;
int i ;
int j ;
int k ;
matrice = (int****)malloc(idim*sizeof(int***));
for(i=0;i<idim;i++)
{
matrice[i] = (int***)malloc(jdim*sizeof(int**));
for(j=0;j<jdim;j++)
{
matrice[i][j] = (int**)malloc(kdim*sizeof(int*));
for(k=0;k<kdim;k++)
{
matrice[i][j][k] = (int*)malloc(ldim*sizeof(int));
}
}
}
return matrice;
}
void del_4D_int(int ****matrice, int idim, int jdim, int kdim)
{
int i ;
int j ;
int k ;
for(i=0;i<idim;i++)
{
for(j=0;j<jdim;j++)
{
for(k=0;k<kdim;k++)
{
free(matrice[i][j][k]);
}
free(matrice[i][j]);
}
free(matrice[i]);
}
free(matrice);
}
void print_vector(int x, int y, int dx, int dy)
{
if (dx != 10000 && dy != 10000){
sum = sum + sqrt((double)dx*(double)dx/w/w + (double)dy*(double)dy/h/h);
count++;
}
//printf("%d %d ; %d %d\n", x, y, dx, dy);
//printf(" %d", dy);
}
/* Print motion vector for each macroblock in this frame. If there is
* no motion vector in some macroblock, it prints a magic number NO_MV. */
void printMVMatrix(int index, AVFrame *pict, AVCodecContext *ctx, int ***MBpart, int ****VectMV, int numFrame)
{
const int mb_width = (ctx->width + 15) / 16;
const int mb_height = (ctx->height + 15) / 16;
const int mb_stride = mb_width + 1;
const int mv_sample_log2 = 4 - pict->motion_subsample_log2;
const int mv_stride = (mb_width << mv_sample_log2) + (ctx->codec_id == CODEC_ID_H264 ? 0 : 1);
const int quarter_sample = (ctx->flags & CODEC_FLAG_QPEL) != 0;
const int shift = 1 + quarter_sample;
//printf("frame %d, %d x %d\n", index, mb_height, mb_width);
for (int mb_y = 0; mb_y < mb_height; mb_y++) {
for (int mb_x = 0; mb_x < mb_width; mb_x++) {
const int mb_index = mb_x + mb_y * mb_stride;
if (pict->motion_val) {
for (int type = 0; type < 3; type++) {
int direction = 0;
switch (type) {
case 0:
if (pict->pict_type != FF_P_TYPE)
{
continue;
}
direction = 0;
break;
case 1:
if (pict->pict_type != FF_B_TYPE)
{
continue;
}
direction = 0;
break;
case 2:
if (pict->pict_type != FF_B_TYPE)
{
continue;
}
direction = 1;
break;
}
if (!USES_LIST(pict->mb_type[mb_index], direction)) {
#define NO_MV 10000
if (IS_8X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 3;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x][1][numFrame] = NO_MV;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = NO_MV;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = NO_MV;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = NO_MV;
} else if (IS_16X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 2;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x][1][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = NO_MV;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = NO_MV;
} else if (IS_8X16(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 1;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x][1][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = NO_MV;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = NO_MV;
} else {
MBpart[mb_y][mb_x][numFrame] = 0;
print_vector(mb_x, mb_y, NO_MV, NO_MV);
VectMV[2*mb_y][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x][1][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = NO_MV;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = NO_MV;
}
#undef NO_MV
continue;
}
if (IS_8X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 3;
for (int i = 0; i < 4; i++) {
int xy = (mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
if(i==0){
VectMV[2*mb_y][2*mb_x][0][numFrame] = dx;
VectMV[2*mb_y][2*mb_x][1][numFrame] = dy;}
if(i==1){
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = dx;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = dy;}
if(i==2){
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = dx;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = dy;}
if(i==3){
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = dx;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = dy;}
}
} else if (IS_16X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 2;
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + (mb_y*2 + i)*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
VectMV[2*mb_y][2*mb_x+i][0][numFrame] = dx;
VectMV[2*mb_y][2*mb_x+i][1][numFrame] = dy;
VectMV[2*mb_y+1][2*mb_x+i][0][numFrame] = dx;
VectMV[2*mb_y+1][2*mb_x+i][1][numFrame] = dy;
}
} else if (IS_8X16(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 1;
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + i + mb_y*2*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
VectMV[2*mb_y+i][2*mb_x][0][numFrame] = dx;
VectMV[2*mb_y+i][2*mb_x][1][numFrame] = dy;
VectMV[2*mb_y+i][2*mb_x+1][0][numFrame] = dx;
VectMV[2*mb_y+i][2*mb_x+1][1][numFrame] = dy;
}
} else {
MBpart[mb_y][mb_x][numFrame] = 0;
int xy = (mb_x + mb_y*mv_stride) << mv_sample_log2;
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
VectMV[2*mb_y][2*mb_x][0][numFrame] = dx;
VectMV[2*mb_y][2*mb_x][1][numFrame] = dy;
VectMV[2*mb_y+1][2*mb_x+1][0][numFrame] = dx;
VectMV[2*mb_y+1][2*mb_x+1][1][numFrame] = dy;
VectMV[2*mb_y+1][2*mb_x][0][numFrame] = dx;
VectMV[2*mb_y+1][2*mb_x][1][numFrame] = dy;
VectMV[2*mb_y][2*mb_x+1][0][numFrame] = dx;
VectMV[2*mb_y][2*mb_x+1][1][numFrame] = dy;
}
}
}
//printf("--\n");
}
//printf("====\n");
}
}
// ====================== Write MV ======================
/* write the MV saved in VectMV in pict*/
void WriteMVMatrix(int index, AVFrame *pict, AVCodecContext *ctx, int ***MBpart, int ****VectMV, int numFrame)
{
const int mb_width = (ctx->width + 15) / 16;
const int mb_height = (ctx->height + 15) / 16;
const int mb_stride = mb_width + 1;
const int mv_sample_log2 = 4 - pict->motion_subsample_log2;
const int mv_stride = (mb_width << mv_sample_log2) + (ctx->codec_id == CODEC_ID_H264 ? 0 : 1);
const int quarter_sample = (ctx->flags & CODEC_FLAG_QPEL) != 0;
const int shift = 1 + quarter_sample;
//printf("frame %d, %d x %d\n", index, mb_height, mb_width);
for (int mb_y = 0; mb_y < mb_height; mb_y++) {
for (int mb_x = 0; mb_x < mb_width; mb_x++) {
const int mb_index = mb_x + mb_y * mb_stride;
if (pict->motion_val) {
for (int type = 0; type < 3; type++) {
int direction = 0;
switch (type) {
case 0:
if (pict->pict_type != FF_P_TYPE)
{
continue;
}
direction = 0;
break;
case 1:
if (pict->pict_type != FF_B_TYPE)
{
continue;
}
direction = 0;
break;
case 2:
if (pict->pict_type != FF_B_TYPE)
{
continue;
}
direction = 1;
break;
}
if (!USES_LIST(pict->mb_type[mb_index], direction)) {
#define NO_MV 10000
if (IS_8X8(pict->mb_type[mb_index])) {
} else if (IS_16X8(pict->mb_type[mb_index])) {
} else if (IS_8X16(pict->mb_type[mb_index])) {
} else {
}
#undef NO_MV
continue;
}
if (IS_8X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 3;
for (int i = 0; i < 4; i++) {
int xy = (mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
if(i==0){
pict->motion_val[direction][xy][0] = VectMV[2*mb_y][2*mb_x][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y][2*mb_x][1][numFrame];}
if(i==1){
pict->motion_val[direction][xy][0] = VectMV[2*mb_y][2*mb_x+1][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y][2*mb_x+1][1][numFrame];}
if(i==2){
pict->motion_val[direction][xy][0] = VectMV[2*mb_y+1][2*mb_x][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y+1][2*mb_x][1][numFrame];}
if(i==3){
pict->motion_val[direction][xy][0] = VectMV[2*mb_y+1][2*mb_x+1][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y+1][2*mb_x+1][1][numFrame];}
}
} else if (IS_16X8(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 2;
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + (mb_y*2 + i)*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
pict->motion_val[direction][xy][0] = VectMV[2*mb_y][2*mb_x+i][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y][2*mb_x+i][1][numFrame];
}
} else if (IS_8X16(pict->mb_type[mb_index])) {
MBpart[mb_y][mb_x][numFrame] = 1;
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + i + mb_y*2*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
pict->motion_val[direction][xy][0] = VectMV[2*mb_y+i][2*mb_x][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y+i][2*mb_x][1][numFrame];
}
} else {
MBpart[mb_y][mb_x][numFrame] = 0;
int xy = (mb_x + mb_y*mv_stride) << mv_sample_log2;
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
pict->motion_val[direction][xy][0] = VectMV[2*mb_y][2*mb_x][0][numFrame];
pict->motion_val[direction][xy][1] = VectMV[2*mb_y][2*mb_x][1][numFrame];
}
}
}
//printf("--\n");
}
//printf("====\n");
}
}
/* Extract info */
int MV_info(const char *name, int *idim, int *jdim, int *Nb, int *GOP)
{
av_register_all();
AVFormatContext *pFormatCtx = NULL;
// Open video file
if(avformat_open_input(&pFormatCtx, name, NULL, NULL)!=0)
return -1; // couldn't open the file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL)<0)
return -1; // couldn't find stream info
// Dump information about file onto standard error
//av_dump_format(pFormatCtx, 0, name, 0);
/* Now pFormatCtx->streams is an array of poiner, of size pFormatCtx->nb_stream, the next lines walks through it until it find a video stream. */
int i;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext *pCodecCtx = NULL;
// Find the first video stream
int videoStream = -1;
for(i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if(videoStream==-1)
return -1; // didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
*idim = (int) (pCodecCtx->height)/16;
*jdim = (int) (pCodecCtx->width)/16;
int N = pCodecCtx->gop_size;
int M = pCodecCtx->max_b_frames;
*GOP = N + N*M/(M+1) - 1; // number of MV map (number of frames + number of B frames (there are 2MVmap) - number of I frames (1))
AVCodec *pCodec = NULL;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
fprintf(stderr, "Unsupported codec !\n");
return -1; // codec not found
}
// Copy context
/*pCodecCtxOrig = avcodec_alloc_context3(pCodec);
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig)!=0)
{
fprintf(stderr, "Couldn't copy codex context");
return -1; // Err copying codec context
}*/
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
return -1; // couldn't open codec
AVFrame *pFrame = NULL;
// Allocate video frame
pFrame = avcodec_alloc_frame();
// read through the entire video stream
int frameFinished;
AVPacket packet;
i = 0;
int f=1;
int NB=0;
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// Is this packet from video stream ?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame ?
if(frameFinished)
{
// Ignore I-Frame
if (pFrame->pict_type != FF_I_TYPE)
{NB = NB +1;}
++f;
}
}
i = i+1;
}
*Nb = NB;
return 1;
}
/* Extract the MB partition and the MV values */
int MV_extract(const char *name, int ****VectMV, int ***MBpart)
{
av_register_all();
AVFormatContext *pFormatCtx = NULL;
// Open video file
if(avformat_open_input(&pFormatCtx, name, NULL, NULL)!=0)
return -1; // couldn't open the file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL)<0)
return -1; // couldn't find stream info
// Dump information about file onto standard error
//av_dump_format(pFormatCtx, 0, name, 0);
/* Now pFormatCtx->streams is an array of poiner, of size pFormatCtx->nb_stream, the next lines walks through it until it find a video stream. */
int i;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext *pCodecCtx = NULL;
// Find the first video stream
int videoStream = -1;
for(i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if(videoStream==-1)
return -1; // didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
/* The stream info about the codec is what we call the "codec context". This contain all the information about the codec that the stream is un=sing, and now we have this pointer to it. We now need to find the actual codec and open it. */
// show some info (size and type of GOP)
printf("\n");
printf("width = %d\n", pCodecCtx->width);
printf("height = %d\n", pCodecCtx->height);
printf("GOP: N%d", pCodecCtx->gop_size);
printf("M%d\n\n", pCodecCtx->max_b_frames);
AVCodec *pCodec = NULL;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
fprintf(stderr, "Unsupported codec !\n");
return -1; // codec not found
}
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
return -1; // couldn't open codec
AVFrame *pFrame = NULL;
// Allocate video frame
pFrame = avcodec_alloc_frame();
// read through the entire video stream
int frameFinished;
AVPacket packet;
i = 0;
int f=1;
int numFrame;
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// Is this packet from video stream ?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame ?
if(frameFinished)
{
// Ignore I-Frame
if (pFrame->pict_type != FF_I_TYPE)
{
printMVMatrix(f, pFrame, pCodecCtx, MBpart, VectMV, numFrame);
numFrame = numFrame + 1;
}
++f;
}
}
i = i+1;
}
return f-1;
}
// ======================= write =======================
/* Write a video with the modified MV stored in VectMV */
int MV_ReadWrite(const char *name, const char *filename, int ****VectMV, int ***MBpart)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int i, ret, x, y, got_output;
int codec_id = AV_CODEC_ID_H264;
FILE *file;
AVFrame *frame;
AVPacket pkt;
uint8_t endcode[] = { 0, 0, 1, 0xb7 };
printf("Encode video file %s\n", filename);
/* find the mpeg video encoder */
codec = avcodec_find_encoder(codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
av_register_all();
AVFormatContext *pFormatCtx = NULL;
// Open video file
if(avformat_open_input(&pFormatCtx, name, NULL, NULL)!=0)
return -1; // couldn't open the file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL)<0)
return -1; // couldn't find stream info
// Dump information about file onto standard error
//av_dump_format(pFormatCtx, 0, name, 0);
/* Now pFormatCtx->streams is an array of poiner, of size pFormatCtx->nb_stream, the next lines walks through it until it find a video stream. */
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext *pCodecCtx = NULL;
// Find the first video stream
int videoStream = -1;
for(i=0; i<pFormatCtx->nb_streams; i++)
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if(videoStream==-1)
return -1; // didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
/* The stream info about the codec is what we call the "codec context". This contain all the information about the codec that the stream is using, and now we have this pointer to it. We now need to find the actual codec and open it. */
/* put sample parameters */
c->bit_rate = pCodecCtx->bit_rate;
/* resolution must be a multiple of two */
c->width = pCodecCtx->width;
c->height = pCodecCtx->height;
/* frames per second */
c->time_base = pCodecCtx->time_base;
c->time_base.den = 25;
/* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
//c->gop_size = pCodecCtx->gop_size;
//c->max_b_frames = pCodecCtx->max_b_frames;
c->pix_fmt = pCodecCtx->pix_fmt;
c->me_method = ME_ZERO; // ME_X1 to use the saved MV
//c->ildct_cmp = 7;
pCodecCtx->me_method = ME_ZERO; // ME_X1 to use the saved MV
printf("%d, %d, %d, %d, %d\n",c->bit_rate,c->gop_size,c->height,c->time_base.num,c->time_base.den);
AVCodec *pCodec = NULL;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
fprintf(stderr, "Unsupported codec !\n");
return -1; // codec not found
}
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
return -1; // couldn't open codec
AVFrame *pFrame = NULL;
// Allocate video frame
pFrame = avcodec_alloc_frame();
int frameFinished;
AVPacket packet;
i = 0;
int f=1;
int numFrame;
// === prepare the new video ===
if (codec_id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data, "preset", "slow", 0);
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
file = fopen(filename, "wb");
if (!file) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = avcodec_alloc_frame();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
/* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used */
ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
c->pix_fmt, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
exit(1);
}
/* ============ encode video ========== */
i=0;
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// Is this packet from video stream ?
if(packet.stream_index==videoStream)
{
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame ?
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
fflush(stdout);
/* prepare a dummy image */
if(frameFinished)
{
// Ignore I-Frame
if (pFrame->pict_type != FF_I_TYPE)
{
WriteMVMatrix(f, pFrame, pCodecCtx, MBpart, VectMV, numFrame);
numFrame = numFrame + 1;
}
++f;
pFrame->pts = i;
/* encode the image */
printf("mb_cmp = %d, me_method = %d\n",c->mb_cmp, c->me_method); // test
ret = avcodec_encode_video2(c, &pkt, pFrame, &got_output); // <= avcodec_encode_video2 estimate the MB partition and the MV value instead of using the ones stored in pFrame /!\
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, file);
av_free_packet(&pkt);
}
i = i+1;
}
}
}
/* get the delayed frames */
for (got_output = 1; got_output; i++) {
fflush(stdout);
ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, file);
av_free_packet(&pkt);
}
}
/* add sequence end code to have a real mpeg file */
fwrite(endcode, 1, sizeof(endcode), file);
fclose(file);
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
//av_frame_free(&frame);
printf("\n");
return f-1;
}
void main()
{
int i,j,k,l;
int ****VectMV;
int ****TestVectMV;
int ***MBpart;
int ***TestMB;
int Nbi,Nbj,Nb,GOP;
const char *name = "001.mp4";
const char *nameOut = "MVtest.mp4";
// Extract info for the allocations
MV_info(name, &Nbi, &Nbj, &Nb, &GOP);
// Allocations
VectMV = new_4D_int(2*Nbi, 2*Nbj, 2, Nb);
TestVectMV = new_4D_int(2*Nbi, 2*Nbj, 2, Nb);
TestMB = new_3D_int(Nbi, Nbj, Nb);
MBpart = new_3D_int(Nbi, Nbj, Nb);
printf("%s\n%d, %d, %d, %d\n", name, Nbi, Nbj, Nb, GOP);
GOP = 1; // useless here
// Extract the MV from the video name
MV_extract(name, VectMV, MBpart);
// To modify the MV
for(i=0;i<Nbi;i++)
{for(j=0;j<Nbj;j++)
{for(k=0;k<2;k++)
{for(l=0;l<Nb;l++)
{//TestVectMV[i][j][k][l] = VectMV[i][j][k][l];
VectMV[i][j][k][l] = VectMV[i][j][k][l] ;
}}}}
// Write the the new video (nameOut) with the new MV (VectMV)
MV_ReadWrite(name, nameOut, VectMV, MBpart);
// Extract the MV from nameOut to verify if MV_ReadWrite worked
MV_extract(nameOut, TestVectMV, TestMB);
// Print Test
for(i=0;i<Nbi;i++)
{for(j=0;j<Nbj;j++)
{for(k=0;k<2;k++)
{for(l=0;l<Nb;l++)
{//printf("%d %d %d\n",TestVectMV[i][j][k][l]-VectMV[i][j][k][l],VectMV[i][j][k][l],TestVectMV[i][j][k][l]);
if(TestMB[i][j][l]!=MBpart[i][j][l]){printf("%d %d %d\n",TestMB[i][j][l]-MBpart[i][j][l],MBpart[i][j][l],TestMB[i][j][l]);} // print when the MB are different
}}}}
del_4D_int(VectMV, 2*Nbi, 2*Nbj, 2);
del_4D_int(TestVectMV, 2*Nbi, 2*Nbj, 2);
del_3D_int(TestMB, Nbi, Nbj);
del_3D_int(MBpart, Nbi, Nbj);
}
_______________________________________________
Libav-user mailing list
[email protected]
http://ffmpeg.org/mailman/listinfo/libav-user