mpeg2enc: Keep the packed data consistent with each parameters
[profile/ivi/libva.git] / test / encode / mpeg2enc.c
index e20814c..73f66be 100644 (file)
@@ -62,8 +62,6 @@
         exit(1);                                                        \
     }
 
-#define INTRA_PERIOD            30
-
 static int const picture_type_patter[][2] = {{VAEncPictureTypeIntra, 1}, 
                                              {VAEncPictureTypePredictive, 3}, {VAEncPictureTypePredictive, 3},{VAEncPictureTypePredictive, 3},
                                              {VAEncPictureTypePredictive, 3}, {VAEncPictureTypePredictive, 3},{VAEncPictureTypePredictive, 3},
@@ -74,6 +72,7 @@ struct mpeg2enc_context {
     /* args */
     int rate_control_mode;
     int fps;
+    int mode; /* 0:I, 1:I/P, 2:I/P/B */
     int width;
     int height;
     int frame_size;
@@ -233,6 +232,7 @@ find_frame_rate_code(const VAEncSequenceParameterBufferMPEG2 *seq_param)
 
         if (abs(1000 * frame_rate_tab[i].value - 1000 * frame_rate_value) < delta) {
             code = frame_rate_tab[i].code;
+            delta = abs(1000 * frame_rate_tab[i].value - 1000 * frame_rate_value);
         }
     }
 
@@ -257,6 +257,8 @@ sps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
     bitstream_put_ui(bs, 0, 1); /* load_intra_quantiser_matrix */
     bitstream_put_ui(bs, 0, 1); /* load_non_intra_quantiser_matrix */
 
+    bitstream_byte_aligning(bs, 0);
+
     bitstream_put_ui(bs, START_CODE_EXT, 32);
     bitstream_put_ui(bs, 1, 4); /* sequence_extension id */
     bitstream_put_ui(bs, seq_param->sequence_extension.bits.profile_and_level_indication, 8);
@@ -271,10 +273,7 @@ sps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
     bitstream_put_ui(bs, seq_param->sequence_extension.bits.frame_rate_extension_n, 2);
     bitstream_put_ui(bs, seq_param->sequence_extension.bits.frame_rate_extension_d, 5);
 
-    bitstream_put_ui(bs, START_CODE_GOP, 32);
-    bitstream_put_ui(bs, seq_param->gop_header.bits.time_code, 25);
-    bitstream_put_ui(bs, seq_param->gop_header.bits.closed_gop, 1);
-    bitstream_put_ui(bs, seq_param->gop_header.bits.broken_link, 1);
+    bitstream_byte_aligning(bs, 0);
 }
 
 static void 
@@ -285,6 +284,15 @@ pps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
     int i;
     int chroma_420_type;
 
+    if (pic_param->temporal_reference == 0) {
+        bitstream_put_ui(bs, START_CODE_GOP, 32);
+        bitstream_put_ui(bs, seq_param->gop_header.bits.time_code, 25);
+        bitstream_put_ui(bs, seq_param->gop_header.bits.closed_gop, 1);
+        bitstream_put_ui(bs, seq_param->gop_header.bits.broken_link, 1);
+
+        bitstream_byte_aligning(bs, 0);
+    }
+
     if (seq_param->sequence_extension.bits.chroma_format == CHROMA_FORMAT_420)
         chroma_420_type = pic_param->picture_coding_extension.bits.progressive_frame;
     else
@@ -310,6 +318,8 @@ pps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
      
     bitstream_put_ui(bs, 0, 1); /* extra_bit_picture, 0 */
 
+    bitstream_byte_aligning(bs, 0);
+
     bitstream_put_ui(bs, START_CODE_EXT, 32);
     bitstream_put_ui(bs, 8, 4); /* Picture Coding Extension ID: 8 */
     bitstream_put_ui(bs, pic_param->f_code[0][0], 4);
@@ -330,12 +340,16 @@ pps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.progressive_frame, 1);
     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.composite_display_flag, 1);
 
+    bitstream_byte_aligning(bs, 0);
+
     if (pic_param->user_data_length) {
         bitstream_put_ui(bs, START_CODE_USER, 32);
 
         for (i = 0; i < pic_param->user_data_length; i++) {
             bitstream_put_ui(bs, pic_param->user_data[i], 8);
         }
+
+        bitstream_byte_aligning(bs, 0);
     }
 }
 
@@ -487,6 +501,7 @@ usage(char *program)
     fprintf(stderr, "where options include:\n");
     fprintf(stderr, "\t--cqp <QP>       const qp mode with specified <QP>\n");
     fprintf(stderr, "\t--fps <FPS>      specify the frame rate\n");
+    fprintf(stderr, "\t--mode <MODE>    specify the mode 0 (I), 1 (I/P) and 2 (I/P/B)\n");
 }
 
 static void 
@@ -499,6 +514,7 @@ parse_args(struct mpeg2enc_context *ctx, int argc, char **argv)
         {"help",        no_argument,            0,      'h'},
         {"cqp",         required_argument,      0,      'c'},
         {"fps",         required_argument,      0,      'f'},
+        {"mode",        required_argument,      0,      'm'},
         { NULL,         0,                      NULL,   0 }
     };
 
@@ -545,6 +561,7 @@ parse_args(struct mpeg2enc_context *ctx, int argc, char **argv)
     ctx->fps = 30;
     ctx->qp = 28;
     ctx->rate_control_mode = VA_RC_CQP;
+    ctx->mode = 1;
 
     optind = 5;
 
@@ -584,6 +601,16 @@ parse_args(struct mpeg2enc_context *ctx, int argc, char **argv)
 
             break;
 
+        case 'm':
+            tmp = atoi(optarg);
+            
+            if (tmp < 0 || tmp > 2)
+                fprintf(stderr, "Waning: MODE must be 0, 1, or 2\n");
+            else
+                ctx->mode = tmp;
+
+            break;
+
         case '?':
             fprintf(stderr, "Error: unkown command options\n");
 
@@ -619,7 +646,7 @@ mpeg2enc_init_sequence_parameter(struct mpeg2enc_context *ctx,
 
     seq_param->frame_rate = ctx->fps;
     seq_param->aspect_ratio_information = 1;
-    seq_param->vbv_buffer_size = 0x10000;
+    seq_param->vbv_buffer_size = 3; /* B = 16 * 1024 * vbv_buffer_size */
 
     seq_param->sequence_extension.bits.profile_and_level_indication = 4 << 4 | 0x8; /* FIXME: Main/Main ??? */
     seq_param->sequence_extension.bits.progressive_sequence = 1; /* progressive frame-pictures */
@@ -644,14 +671,14 @@ mpeg2enc_init_picture_parameter(struct mpeg2enc_context *ctx,
     pic_param->picture_type = VAEncPictureTypeIntra;
 
     pic_param->temporal_reference = 0;
-    pic_param->f_code[0][0] = 1;
-    pic_param->f_code[0][1] = 1;
-    pic_param->f_code[1][0] = 1;
-    pic_param->f_code[1][1] = 1;
+    pic_param->f_code[0][0] = 0xf;
+    pic_param->f_code[0][1] = 0xf;
+    pic_param->f_code[1][0] = 0xf;
+    pic_param->f_code[1][1] = 0xf;
 
     pic_param->picture_coding_extension.bits.intra_dc_precision = 0; /* 8bits */
     pic_param->picture_coding_extension.bits.picture_structure = 3; /* frame picture */
-    pic_param->picture_coding_extension.bits.top_field_first = 1
+    pic_param->picture_coding_extension.bits.top_field_first = 0
     pic_param->picture_coding_extension.bits.frame_pred_frame_dct = 1; /* FIXME */
     pic_param->picture_coding_extension.bits.concealment_motion_vectors = 0;
     pic_param->picture_coding_extension.bits.q_scale_type = 0;
@@ -766,7 +793,12 @@ mpeg2enc_init(struct mpeg2enc_context *ctx)
     ctx->codedbuf_buf_id = VA_INVALID_ID;
     ctx->codedbuf_i_size = ctx->frame_size;
     ctx->codedbuf_pb_size = 0;
-    ctx->intra_period = INTRA_PERIOD;
+
+    if (ctx->mode == 0)
+        ctx->intra_period = 1;
+    else
+        ctx->intra_period = 16;
+
     ctx->bit_rate = -1;
 
     for (i = 0; i < MAX_SLICES; i++) {
@@ -786,27 +818,82 @@ mpeg2enc_init(struct mpeg2enc_context *ctx)
                                               ctx);
 }
 
+static int 
+mpeg2enc_time_code(VAEncSequenceParameterBufferMPEG2 *seq_param,
+                   int num_frames)
+{
+    int fps = (int)(seq_param->frame_rate + 0.5);
+    int time_code = 0;
+    int time_code_pictures, time_code_seconds, time_code_minutes, time_code_hours;
+    int drop_frame_flag = 0;
+
+    assert(fps <= 60);
+
+    time_code_seconds = num_frames / fps;
+    time_code_pictures = num_frames % fps;
+    time_code |= time_code_pictures;
+
+    time_code_minutes = time_code_minutes / 60;
+    time_code_seconds = time_code_minutes % 60;
+    time_code |= (time_code_seconds << 6);
+
+    time_code_hours = time_code_minutes / 60;
+    time_code_minutes = time_code_minutes % 60;
+
+    time_code |= (1 << 12);     /* marker_bit */
+    time_code |= (time_code_minutes << 13);
+
+    time_code_hours = time_code_hours % 24;
+    time_code |= (time_code_hours << 19);
+
+    time_code |= (drop_frame_flag << 24);
+
+    return time_code;
+}
+
 /*
  * run
  */
-static void 
+static void
+mpeg2enc_update_sequence_parameter(struct mpeg2enc_context *ctx,
+                                   VAEncPictureType picture_type,
+                                   int coded_order,
+                                   int display_order)
+{
+    VAEncSequenceParameterBufferMPEG2 *seq_param = &ctx->seq_param;
+
+    /* update the GOP info for the new GOP */
+    if (display_order % ctx->intra_period == 0) {
+        seq_param->gop_header.bits.time_code = mpeg2enc_time_code(seq_param, display_order);
+    }
+}
+
+static void
 mpeg2enc_update_picture_parameter(struct mpeg2enc_context *ctx,
-                                 VAEncPictureType picture_type,
-                                 int coded_order,
-                                 int display_order)
+                                  VAEncPictureType picture_type,
+                                  int coded_order,
+                                  int display_order)
 {
-    VAEncPictureParameterBufferMPEG2 *pic_param;
-    VAStatus va_status;
+    VAEncPictureParameterBufferMPEG2 *pic_param = &ctx->pic_param;
 
-    // Picture level
-    pic_param = &ctx->pic_param;
     pic_param->picture_type = picture_type;
-    pic_param->temporal_reference = display_order;
+    pic_param->temporal_reference = display_order % ctx->intra_period;
     pic_param->reconstructed_picture = surface_ids[SID_RECON_PICTURE];
     pic_param->forward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L0];
     pic_param->backward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L1];
-    pic_param->coded_buf = ctx->codedbuf_buf_id;
+}
+
+static void
+mpeg2enc_update_picture_parameter_buffer(struct mpeg2enc_context *ctx,
+                                         VAEncPictureType picture_type,
+                                         int coded_order,
+                                         int display_order)
+{
+    VAEncPictureParameterBufferMPEG2 *pic_param = &ctx->pic_param;
+    VAStatus va_status;
 
+    /* update the coded buffer id */
+    pic_param->coded_buf = ctx->codedbuf_buf_id;
     va_status = vaCreateBuffer(ctx->va_dpy,
                                ctx->context_id,
                                VAEncPictureParameterBufferType,
@@ -860,6 +947,9 @@ begin_picture(struct mpeg2enc_context *ctx,
 {
     VAStatus va_status;
     int tmp;
+    VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
+    unsigned int length_in_bits;
+    unsigned char *packed_seq_buffer = NULL, *packed_pic_buffer = NULL;
 
     if (ctx->upload_thread_value != 0) {
         fprintf(stderr, "FATAL error!!!\n");
@@ -873,11 +963,10 @@ begin_picture(struct mpeg2enc_context *ctx,
     ctx->current_input_surface = ctx->current_upload_surface;
     ctx->current_upload_surface = tmp;
 
-    if (coded_order == 0) {
-        VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
-        unsigned int length_in_bits;
-        unsigned char *packed_seq_buffer = NULL, *packed_pic_buffer = NULL;
+    mpeg2enc_update_sequence_parameter(ctx, picture_type, coded_order, display_order);
+    mpeg2enc_update_picture_parameter(ctx, picture_type, coded_order, display_order);
 
+    if (coded_order == 0) {
         assert(picture_type == VAEncPictureTypeIntra);
         length_in_bits = build_packed_seq_buffer(&ctx->seq_param, &packed_seq_buffer);
         packed_header_param_buffer.type = VAEncPackedHeaderMPEG2_SPS;
@@ -897,28 +986,29 @@ begin_picture(struct mpeg2enc_context *ctx,
                                    &ctx->packed_seq_buf_id);
         CHECK_VASTATUS(va_status,"vaCreateBuffer");
 
-        length_in_bits = build_packed_pic_buffer(&ctx->seq_param, &ctx->pic_param, &packed_pic_buffer);
-        packed_header_param_buffer.type = VAEncPackedHeaderMPEG2_PPS;
-        packed_header_param_buffer.has_emulation_bytes = 0;
-        packed_header_param_buffer.bit_length = length_in_bits;
+        free(packed_seq_buffer);
+    }
 
-        va_status = vaCreateBuffer(ctx->va_dpy,
-                                   ctx->context_id,
-                                   VAEncPackedHeaderParameterBufferType,
-                                   sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
-                                   &ctx->packed_pic_header_param_buf_id);
-        CHECK_VASTATUS(va_status,"vaCreateBuffer");
+    length_in_bits = build_packed_pic_buffer(&ctx->seq_param, &ctx->pic_param, &packed_pic_buffer);
+    packed_header_param_buffer.type = VAEncPackedHeaderMPEG2_PPS;
+    packed_header_param_buffer.has_emulation_bytes = 0;
+    packed_header_param_buffer.bit_length = length_in_bits;
 
-        va_status = vaCreateBuffer(ctx->va_dpy,
-                                   ctx->context_id,
-                                   VAEncPackedHeaderDataBufferType,
-                                   (length_in_bits + 7) / 8, 1, packed_pic_buffer,
-                                   &ctx->packed_pic_buf_id);
-        CHECK_VASTATUS(va_status,"vaCreateBuffer");
+    va_status = vaCreateBuffer(ctx->va_dpy,
+                               ctx->context_id,
+                               VAEncPackedHeaderParameterBufferType,
+                               sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
+                               &ctx->packed_pic_header_param_buf_id);
+    CHECK_VASTATUS(va_status,"vaCreateBuffer");
 
-        free(packed_seq_buffer);
-        free(packed_pic_buffer);
-    }
+    va_status = vaCreateBuffer(ctx->va_dpy,
+                               ctx->context_id,
+                               VAEncPackedHeaderDataBufferType,
+                               (length_in_bits + 7) / 8, 1, packed_pic_buffer,
+                               &ctx->packed_pic_buf_id);
+    CHECK_VASTATUS(va_status,"vaCreateBuffer");
+
+    free(packed_pic_buffer);
 
     /* sequence parameter set */
     VAEncSequenceParameterBufferMPEG2 *seq_param = &ctx->seq_param;
@@ -1136,7 +1226,7 @@ encode_picture(struct mpeg2enc_context *ctx,
         CHECK_VASTATUS(va_status,"vaCreateBuffer");
 
         /* picture parameter set */
-        mpeg2enc_update_picture_parameter(ctx, picture_type, coded_order, display_order);
+        mpeg2enc_update_picture_parameter_buffer(ctx, picture_type, coded_order, display_order);
 
         mpeg2enc_render_picture(ctx);
 
@@ -1183,10 +1273,9 @@ static void
 mpeg2enc_run(struct mpeg2enc_context *ctx)
 {
     int display_order = 0, coded_order = 0;
-    int i_frame_only = 1, i_p_frame_only = 1;
 
     for (display_order = 0; display_order < ctx->num_pictures;) {
-        if (i_frame_only) {
+        if (ctx->mode == 0) {
             encode_picture(ctx,
                            coded_order,
                            display_order,
@@ -1195,7 +1284,8 @@ mpeg2enc_run(struct mpeg2enc_context *ctx)
                            display_order + 1);
             display_order++;
             coded_order++;
-        } else if (i_p_frame_only) {
+        } else if (ctx->mode == 1) {
+            assert(0);
             if ((display_order % ctx->intra_period) == 0) {
                 encode_picture(ctx,
                                coded_order,
@@ -1218,6 +1308,8 @@ mpeg2enc_run(struct mpeg2enc_context *ctx)
         } else { // follow the i,p,b pattern
             static int fcurrent = 0;
             int fnext;
+
+            assert(0);
             
             fcurrent = fcurrent % (sizeof(picture_type_patter)/sizeof(int[2]));
             fnext = (fcurrent+1) % (sizeof(picture_type_patter)/sizeof(int[2]));