Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the
  6.  * "Software"), to deal in the Software without restriction, including
  7.  * without limitation the rights to use, copy, modify, merge, publish,
  8.  * distribute, sub license, and/or sell copies of the Software, and to
  9.  * permit persons to whom the Software is furnished to do so, subject to
  10.  * the following conditions:
  11.  *
  12.  * The above copyright notice and this permission notice (including the
  13.  * next paragraph) shall be included in all copies or substantial portions
  14.  * of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  19.  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
  20.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23.  */
  24. /*
  25.  * Simple MPEG-2 encoder based on libVA.
  26.  *
  27.  */  
  28.  
  29. #include "sysdeps.h"
  30.  
  31. #include <getopt.h>
  32. #include <unistd.h>
  33.  
  34. #include <sys/time.h>
  35. #include <sys/types.h>
  36. #include <fcntl.h>
  37. #include <time.h>
  38. #include <pthread.h>
  39.  
  40. #include <va/va.h>
  41. #include <va/va_enc_mpeg2.h>
  42.  
  43. #include "va_display.h"
  44.  
  45. #define START_CODE_PICUTRE      0x00000100
  46. #define START_CODE_SLICE        0x00000101
  47. #define START_CODE_USER         0x000001B2
  48. #define START_CODE_SEQ          0x000001B3
  49. #define START_CODE_EXT          0x000001B5
  50. #define START_CODE_GOP          0x000001B8
  51.  
  52. #define CHROMA_FORMAT_RESERVED  0
  53. #define CHROMA_FORMAT_420       1
  54. #define CHROMA_FORMAT_422       2
  55. #define CHROMA_FORMAT_444       3
  56.  
  57. #define MAX_SLICES              128
  58.  
  59. enum {
  60.     MPEG2_MODE_I = 0,
  61.     MPEG2_MODE_IP,
  62.     MPEG2_MODE_IPB,
  63. };
  64.  
  65. enum {
  66.     MPEG2_LEVEL_LOW = 0,
  67.     MPEG2_LEVEL_MAIN,
  68.     MPEG2_LEVEL_HIGH,
  69. };
  70.  
  71. #define CHECK_VASTATUS(va_status, func)                                 \
  72.     if (va_status != VA_STATUS_SUCCESS) {                               \
  73.         fprintf(stderr, "%s:%s (%d) failed, exit\n", __func__, func, __LINE__); \
  74.         exit(1);                                                        \
  75.     }
  76.  
  77. static VAProfile mpeg2_va_profiles[] = {
  78.     VAProfileMPEG2Simple,
  79.     VAProfileMPEG2Main
  80. };
  81.  
  82. static struct _mpeg2_sampling_density
  83. {
  84.     int samplers_per_line;
  85.     int line_per_frame;
  86.     int frame_per_sec;
  87. } mpeg2_upper_samplings[2][3] = {
  88.     { { 0, 0, 0 },
  89.       { 720, 576, 30 },
  90.       { 0, 0, 0 },
  91.     },
  92.  
  93.     { { 352, 288, 30 },
  94.       { 720, 576, 30 },
  95.       { 1920, 1152, 60 },
  96.     }
  97. };
  98.  
  99. struct mpeg2enc_context {
  100.     /* args */
  101.     int rate_control_mode;
  102.     int fps;
  103.     int mode; /* 0:I, 1:I/P, 2:I/P/B */
  104.     VAProfile profile;
  105.     int level;
  106.     int width;
  107.     int height;
  108.     int frame_size;
  109.     int num_pictures;
  110.     int qp;
  111.     FILE *ifp;
  112.     FILE *ofp;
  113.     unsigned char *frame_data_buffer;
  114.     int intra_period;
  115.     int ip_period;
  116.     int bit_rate; /* in kbps */
  117.     VAEncPictureType next_type;
  118.     int next_display_order;
  119.     int next_bframes;
  120.     int new_sequence;
  121.     int new_gop_header;
  122.     int gop_header_in_display_order;
  123.  
  124.     /* VA resource */
  125.     VADisplay va_dpy;
  126.     VAEncSequenceParameterBufferMPEG2 seq_param;
  127.     VAEncPictureParameterBufferMPEG2 pic_param;
  128.     VAEncSliceParameterBufferMPEG2 slice_param[MAX_SLICES];
  129.     VAContextID context_id;
  130.     VAConfigID config_id;
  131.     VABufferID seq_param_buf_id;                /* Sequence level parameter */
  132.     VABufferID pic_param_buf_id;                /* Picture level parameter */
  133.     VABufferID slice_param_buf_id[MAX_SLICES];  /* Slice level parameter, multil slices */
  134.     VABufferID codedbuf_buf_id;                 /* Output buffer, compressed data */
  135.     VABufferID packed_seq_header_param_buf_id;
  136.     VABufferID packed_seq_buf_id;
  137.     VABufferID packed_pic_header_param_buf_id;
  138.     VABufferID packed_pic_buf_id;
  139.     int num_slice_groups;
  140.     int codedbuf_i_size;
  141.     int codedbuf_pb_size;
  142.  
  143.     /* thread */
  144.     pthread_t upload_thread_id;
  145.     int upload_thread_value;
  146.     int current_input_surface;
  147.     int current_upload_surface;
  148. };
  149.  
  150. /*
  151.  * mpeg2enc helpers
  152.  */
  153. #define BITSTREAM_ALLOCATE_STEPPING     4096
  154.  
  155. struct __bitstream {
  156.     unsigned int *buffer;
  157.     int bit_offset;
  158.     int max_size_in_dword;
  159. };
  160.  
  161. typedef struct __bitstream bitstream;
  162.  
  163. static unsigned int
  164. swap32(unsigned int val)
  165. {
  166.     unsigned char *pval = (unsigned char *)&val;
  167.  
  168.     return ((pval[0] << 24)     |
  169.             (pval[1] << 16)     |
  170.             (pval[2] << 8)      |
  171.             (pval[3] << 0));
  172. }
  173.  
  174. static void
  175. bitstream_start(bitstream *bs)
  176. {
  177.     bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
  178.     bs->buffer = calloc(bs->max_size_in_dword * sizeof(int), 1);
  179.     bs->bit_offset = 0;
  180. }
  181.  
  182. static void
  183. bitstream_end(bitstream *bs)
  184. {
  185.     int pos = (bs->bit_offset >> 5);
  186.     int bit_offset = (bs->bit_offset & 0x1f);
  187.     int bit_left = 32 - bit_offset;
  188.  
  189.     if (bit_offset) {
  190.         bs->buffer[pos] = swap32((bs->buffer[pos] << bit_left));
  191.     }
  192. }
  193.  
  194. static void
  195. bitstream_put_ui(bitstream *bs, unsigned int val, int size_in_bits)
  196. {
  197.     int pos = (bs->bit_offset >> 5);
  198.     int bit_offset = (bs->bit_offset & 0x1f);
  199.     int bit_left = 32 - bit_offset;
  200.  
  201.     if (!size_in_bits)
  202.         return;
  203.  
  204.     if (size_in_bits < 32)
  205.         val &= ((1 << size_in_bits) - 1);
  206.  
  207.     bs->bit_offset += size_in_bits;
  208.  
  209.     if (bit_left > size_in_bits) {
  210.         bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
  211.     } else {
  212.         size_in_bits -= bit_left;
  213.         bs->buffer[pos] = (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
  214.         bs->buffer[pos] = swap32(bs->buffer[pos]);
  215.  
  216.         if (pos + 1 == bs->max_size_in_dword) {
  217.             bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
  218.             bs->buffer = realloc(bs->buffer, bs->max_size_in_dword * sizeof(unsigned int));
  219.         }
  220.  
  221.         bs->buffer[pos + 1] = val;
  222.     }
  223. }
  224.  
  225. static void
  226. bitstream_byte_aligning(bitstream *bs, int bit)
  227. {
  228.     int bit_offset = (bs->bit_offset & 0x7);
  229.     int bit_left = 8 - bit_offset;
  230.     int new_val;
  231.  
  232.     if (!bit_offset)
  233.         return;
  234.  
  235.     assert(bit == 0 || bit == 1);
  236.  
  237.     if (bit)
  238.         new_val = (1 << bit_left) - 1;
  239.     else
  240.         new_val = 0;
  241.  
  242.     bitstream_put_ui(bs, new_val, bit_left);
  243. }
  244.  
  245. static struct mpeg2_frame_rate {
  246.     int code;
  247.     float value;
  248. } frame_rate_tab[] = {
  249.     {1, 23.976},
  250.     {2, 24.0},
  251.     {3, 25.0},
  252.     {4, 29.97},
  253.     {5, 30},
  254.     {6, 50},
  255.     {7, 59.94},
  256.     {8, 60}
  257. };
  258.  
  259. static int
  260. find_frame_rate_code(const VAEncSequenceParameterBufferMPEG2 *seq_param)
  261. {
  262.     unsigned int delta = -1;
  263.     int code = 1, i;
  264.     float frame_rate_value = seq_param->frame_rate *
  265.         (seq_param->sequence_extension.bits.frame_rate_extension_d + 1) /
  266.         (seq_param->sequence_extension.bits.frame_rate_extension_n + 1);
  267.  
  268.     for (i = 0; i < sizeof(frame_rate_tab) / sizeof(frame_rate_tab[0]); i++) {
  269.  
  270.         if (abs(1000 * frame_rate_tab[i].value - 1000 * frame_rate_value) < delta) {
  271.             code = frame_rate_tab[i].code;
  272.             delta = abs(1000 * frame_rate_tab[i].value - 1000 * frame_rate_value);
  273.         }
  274.     }
  275.  
  276.     return code;
  277. }
  278.  
  279. static void
  280. sps_rbsp(struct mpeg2enc_context *ctx,
  281.          const VAEncSequenceParameterBufferMPEG2 *seq_param,
  282.          bitstream *bs)
  283. {
  284.     int frame_rate_code = find_frame_rate_code(seq_param);
  285.  
  286.     if (ctx->new_sequence) {
  287.         bitstream_put_ui(bs, START_CODE_SEQ, 32);
  288.         bitstream_put_ui(bs, seq_param->picture_width, 12);
  289.         bitstream_put_ui(bs, seq_param->picture_height, 12);
  290.         bitstream_put_ui(bs, seq_param->aspect_ratio_information, 4);
  291.         bitstream_put_ui(bs, frame_rate_code, 4); /* frame_rate_code */
  292.         bitstream_put_ui(bs, (seq_param->bits_per_second + 399) / 400, 18); /* the low 18 bits of bit_rate */
  293.         bitstream_put_ui(bs, 1, 1); /* marker_bit */
  294.         bitstream_put_ui(bs, seq_param->vbv_buffer_size, 10);
  295.         bitstream_put_ui(bs, 0, 1); /* constraint_parameter_flag, always 0 for MPEG-2 */
  296.         bitstream_put_ui(bs, 0, 1); /* load_intra_quantiser_matrix */
  297.         bitstream_put_ui(bs, 0, 1); /* load_non_intra_quantiser_matrix */
  298.  
  299.         bitstream_byte_aligning(bs, 0);
  300.  
  301.         bitstream_put_ui(bs, START_CODE_EXT, 32);
  302.         bitstream_put_ui(bs, 1, 4); /* sequence_extension id */
  303.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.profile_and_level_indication, 8);
  304.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.progressive_sequence, 1);
  305.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.chroma_format, 2);
  306.         bitstream_put_ui(bs, seq_param->picture_width >> 12, 2);
  307.         bitstream_put_ui(bs, seq_param->picture_height >> 12, 2);
  308.         bitstream_put_ui(bs, ((seq_param->bits_per_second + 399) / 400) >> 18, 12); /* bit_rate_extension */
  309.         bitstream_put_ui(bs, 1, 1); /* marker_bit */
  310.         bitstream_put_ui(bs, seq_param->vbv_buffer_size >> 10, 8);
  311.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.low_delay, 1);
  312.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.frame_rate_extension_n, 2);
  313.         bitstream_put_ui(bs, seq_param->sequence_extension.bits.frame_rate_extension_d, 5);
  314.  
  315.         bitstream_byte_aligning(bs, 0);
  316.     }
  317.  
  318.     if (ctx->new_gop_header) {
  319.         bitstream_put_ui(bs, START_CODE_GOP, 32);
  320.         bitstream_put_ui(bs, seq_param->gop_header.bits.time_code, 25);
  321.         bitstream_put_ui(bs, seq_param->gop_header.bits.closed_gop, 1);
  322.         bitstream_put_ui(bs, seq_param->gop_header.bits.broken_link, 1);
  323.  
  324.         bitstream_byte_aligning(bs, 0);
  325.     }
  326. }
  327.  
  328. static void
  329. pps_rbsp(const VAEncSequenceParameterBufferMPEG2 *seq_param,
  330.          const VAEncPictureParameterBufferMPEG2 *pic_param,
  331.          bitstream *bs)
  332. {
  333.     int chroma_420_type;
  334.  
  335.     if (seq_param->sequence_extension.bits.chroma_format == CHROMA_FORMAT_420)
  336.         chroma_420_type = pic_param->picture_coding_extension.bits.progressive_frame;
  337.     else
  338.         chroma_420_type = 0;
  339.  
  340.     bitstream_put_ui(bs, START_CODE_PICUTRE, 32);
  341.     bitstream_put_ui(bs, pic_param->temporal_reference, 10);
  342.     bitstream_put_ui(bs,
  343.                      pic_param->picture_type == VAEncPictureTypeIntra ? 1 :
  344.                      pic_param->picture_type == VAEncPictureTypePredictive ? 2 : 3,
  345.                      3);
  346.     bitstream_put_ui(bs, 0xFFFF, 16); /* vbv_delay, always 0xFFFF */
  347.    
  348.     if (pic_param->picture_type == VAEncPictureTypePredictive ||
  349.         pic_param->picture_type == VAEncPictureTypeBidirectional) {
  350.         bitstream_put_ui(bs, 0, 1); /* full_pel_forward_vector, always 0 for MPEG-2 */
  351.         bitstream_put_ui(bs, 7, 3); /* forward_f_code, always 7 for MPEG-2 */
  352.     }
  353.  
  354.     if (pic_param->picture_type == VAEncPictureTypeBidirectional) {
  355.         bitstream_put_ui(bs, 0, 1); /* full_pel_backward_vector, always 0 for MPEG-2 */
  356.         bitstream_put_ui(bs, 7, 3); /* backward_f_code, always 7 for MPEG-2 */
  357.     }
  358.      
  359.     bitstream_put_ui(bs, 0, 1); /* extra_bit_picture, 0 */
  360.  
  361.     bitstream_byte_aligning(bs, 0);
  362.  
  363.     bitstream_put_ui(bs, START_CODE_EXT, 32);
  364.     bitstream_put_ui(bs, 8, 4); /* Picture Coding Extension ID: 8 */
  365.     bitstream_put_ui(bs, pic_param->f_code[0][0], 4);
  366.     bitstream_put_ui(bs, pic_param->f_code[0][1], 4);
  367.     bitstream_put_ui(bs, pic_param->f_code[1][0], 4);
  368.     bitstream_put_ui(bs, pic_param->f_code[1][1], 4);
  369.  
  370.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.intra_dc_precision, 2);
  371.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.picture_structure, 2);
  372.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.top_field_first, 1);
  373.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.frame_pred_frame_dct, 1);
  374.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.concealment_motion_vectors, 1);
  375.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.q_scale_type, 1);
  376.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.intra_vlc_format, 1);
  377.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.alternate_scan, 1);
  378.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.repeat_first_field, 1);
  379.     bitstream_put_ui(bs, chroma_420_type, 1);
  380.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.progressive_frame, 1);
  381.     bitstream_put_ui(bs, pic_param->picture_coding_extension.bits.composite_display_flag, 1);
  382.  
  383.     bitstream_byte_aligning(bs, 0);
  384. }
  385.  
  386. static int
  387. build_packed_pic_buffer(const VAEncSequenceParameterBufferMPEG2 *seq_param,
  388.                         const VAEncPictureParameterBufferMPEG2 *pic_param,
  389.                         unsigned char **header_buffer)
  390. {
  391.     bitstream bs;
  392.  
  393.     bitstream_start(&bs);
  394.     pps_rbsp(seq_param, pic_param, &bs);
  395.     bitstream_end(&bs);
  396.  
  397.     *header_buffer = (unsigned char *)bs.buffer;
  398.     return bs.bit_offset;
  399. }
  400.  
  401. static int
  402. build_packed_seq_buffer(struct mpeg2enc_context *ctx,
  403.                         const VAEncSequenceParameterBufferMPEG2 *seq_param,
  404.                         unsigned char **header_buffer)
  405. {
  406.     bitstream bs;
  407.  
  408.     bitstream_start(&bs);
  409.     sps_rbsp(ctx, seq_param, &bs);
  410.     bitstream_end(&bs);
  411.  
  412.     *header_buffer = (unsigned char *)bs.buffer;
  413.     return bs.bit_offset;
  414. }
  415.  
  416. /*
  417.  * mpeg2enc
  418.  */
  419. #define SID_INPUT_PICTURE_0                     0
  420. #define SID_INPUT_PICTURE_1                     1
  421. #define SID_REFERENCE_PICTURE_L0                2
  422. #define SID_REFERENCE_PICTURE_L1                3
  423. #define SID_RECON_PICTURE                       4
  424. #define SID_NUMBER                              SID_RECON_PICTURE + 1
  425.  
  426. static VASurfaceID surface_ids[SID_NUMBER];
  427.  
  428. /*
  429.  * upload thread function
  430.  */
  431. static void *
  432. upload_yuv_to_surface(void *data)
  433. {
  434.     struct mpeg2enc_context *ctx = data;
  435.     VAImage surface_image;
  436.     VAStatus va_status;
  437.     void *surface_p = NULL;
  438.     unsigned char *y_src, *u_src, *v_src;
  439.     unsigned char *y_dst, *u_dst, *v_dst;
  440.     int y_size = ctx->width * ctx->height;
  441.     int u_size = (ctx->width >> 1) * (ctx->height >> 1);
  442.     int row, col;
  443.     size_t n_items;
  444.  
  445.     do {
  446.         n_items = fread(ctx->frame_data_buffer, ctx->frame_size, 1, ctx->ifp);
  447.     } while (n_items != 1);
  448.  
  449.     va_status = vaDeriveImage(ctx->va_dpy, surface_ids[ctx->current_upload_surface], &surface_image);
  450.     CHECK_VASTATUS(va_status,"vaDeriveImage");
  451.  
  452.     vaMapBuffer(ctx->va_dpy, surface_image.buf, &surface_p);
  453.     assert(VA_STATUS_SUCCESS == va_status);
  454.        
  455.     y_src = ctx->frame_data_buffer;
  456.     u_src = ctx->frame_data_buffer + y_size; /* UV offset for NV12 */
  457.     v_src = ctx->frame_data_buffer + y_size + u_size;
  458.  
  459.     y_dst = surface_p + surface_image.offsets[0];
  460.     u_dst = surface_p + surface_image.offsets[1]; /* UV offset for NV12 */
  461.     v_dst = surface_p + surface_image.offsets[2];
  462.  
  463.     /* Y plane */
  464.     for (row = 0; row < surface_image.height; row++) {
  465.         memcpy(y_dst, y_src, surface_image.width);
  466.         y_dst += surface_image.pitches[0];
  467.         y_src += ctx->width;
  468.     }
  469.  
  470.     if (surface_image.format.fourcc == VA_FOURCC_NV12) { /* UV plane */
  471.         for (row = 0; row < surface_image.height / 2; row++) {
  472.             for (col = 0; col < surface_image.width / 2; col++) {
  473.                 u_dst[col * 2] = u_src[col];
  474.                 u_dst[col * 2 + 1] = v_src[col];
  475.             }
  476.  
  477.             u_dst += surface_image.pitches[1];
  478.             u_src += (ctx->width / 2);
  479.             v_src += (ctx->width / 2);
  480.         }
  481.     } else {
  482.         for (row = 0; row < surface_image.height / 2; row++) {
  483.             for (col = 0; col < surface_image.width / 2; col++) {
  484.                 u_dst[col] = u_src[col];
  485.                 v_dst[col] = v_src[col];
  486.             }
  487.  
  488.             u_dst += surface_image.pitches[1];
  489.             v_dst += surface_image.pitches[2];
  490.             u_src += (ctx->width / 2);
  491.             v_src += (ctx->width / 2);
  492.         }
  493.     }
  494.  
  495.     vaUnmapBuffer(ctx->va_dpy, surface_image.buf);
  496.     vaDestroyImage(ctx->va_dpy, surface_image.image_id);
  497.  
  498.     return NULL;
  499. }
  500.  
  501. static void
  502. mpeg2enc_exit(struct mpeg2enc_context *ctx, int exit_code)
  503. {
  504.     if (ctx->frame_data_buffer) {
  505.         free(ctx->frame_data_buffer);
  506.         ctx->frame_data_buffer = NULL;
  507.     }
  508.  
  509.     if (ctx->ifp) {
  510.         fclose(ctx->ifp);
  511.         ctx->ifp = NULL;
  512.     }
  513.  
  514.     if (ctx->ofp) {
  515.         fclose(ctx->ofp);
  516.         ctx->ofp = NULL;
  517.     }
  518.  
  519.     exit(exit_code);
  520. }
  521.  
  522. static void
  523. usage(char *program)
  524. {  
  525.     fprintf(stderr, "Usage: %s --help\n", program);
  526.     fprintf(stderr, "\t--help   print this message\n");
  527.     fprintf(stderr, "Usage: %s <width> <height> <ifile> <ofile> [options]\n", program);
  528.     fprintf(stderr, "\t<width>  specifies the frame width\n");
  529.     fprintf(stderr, "\t<height> specifies the frame height\n");
  530.     fprintf(stderr, "\t<ifile>  specifies the I420/IYUV YUV file\n");
  531.     fprintf(stderr, "\t<ofile>  specifies the encoded MPEG-2 file\n");
  532.     fprintf(stderr, "where options include:\n");
  533.     fprintf(stderr, "\t--cqp <QP>       const qp mode with specified <QP>\n");
  534.     fprintf(stderr, "\t--fps <FPS>      specify the frame rate\n");
  535.     fprintf(stderr, "\t--mode <MODE>    specify the mode 0 (I), 1 (I/P) and 2 (I/P/B)\n");
  536.     fprintf(stderr, "\t--profile <PROFILE>      specify the profile 0(Simple), or 1(Main, default)\n");
  537.     fprintf(stderr, "\t--level <LEVEL>  specify the level 0(Low), 1(Main, default) or 2(High)\n");    
  538. }
  539.  
  540. void
  541. mpeg2_profile_level(struct mpeg2enc_context *ctx,
  542.                     int profile,
  543.                     int level)
  544. {
  545.     int l = 2, p;
  546.  
  547.     for (p = profile; p < 2; p++) {
  548.         for (l = level; l < 3; l++) {
  549.             if (ctx->width <= mpeg2_upper_samplings[p][l].samplers_per_line &&
  550.                 ctx->height <= mpeg2_upper_samplings[p][l].line_per_frame &&
  551.                 ctx->fps <= mpeg2_upper_samplings[p][l].frame_per_sec) {
  552.                
  553.                 goto __find;
  554.                 break;
  555.             }
  556.         }
  557.     }
  558.  
  559.     if (p == 2) {
  560.         fprintf(stderr, "Warning: can't find a proper profile and level for the specified width/height/fps\n");
  561.         p = 1;
  562.         l = 2;
  563.     }
  564.  
  565. __find:    
  566.     ctx->profile = mpeg2_va_profiles[p];
  567.     ctx->level = l;
  568. }
  569.  
  570. static void
  571. parse_args(struct mpeg2enc_context *ctx, int argc, char **argv)
  572. {
  573.     int c, tmp;
  574.     int option_index = 0;
  575.     long file_size;
  576.     int profile = 1, level = 1;
  577.  
  578.     static struct option long_options[] = {
  579.         {"help",        no_argument,            0,      'h'},
  580.         {"cqp",         required_argument,      0,      'c'},
  581.         {"fps",         required_argument,      0,      'f'},
  582.         {"mode",        required_argument,      0,      'm'},
  583.         {"profile",     required_argument,      0,      'p'},
  584.         {"level",       required_argument,      0,      'l'},
  585.         { NULL,         0,                      NULL,   0 }
  586.     };
  587.  
  588.     if ((argc == 2 && strcmp(argv[1], "--help") == 0) ||
  589.         (argc < 5))
  590.         goto print_usage;
  591.  
  592.     ctx->width = atoi(argv[1]);
  593.     ctx->height = atoi(argv[2]);
  594.  
  595.     if (ctx->width <= 0 || ctx->height <= 0) {
  596.         fprintf(stderr, "<width> and <height> must be greater than 0\n");
  597.         goto err_exit;
  598.     }
  599.  
  600.     ctx->ifp = fopen(argv[3], "rb");
  601.  
  602.     if (ctx->ifp == NULL) {
  603.         fprintf(stderr, "Can't open the input file\n");
  604.         goto err_exit;
  605.     }
  606.  
  607.     fseek(ctx->ifp, 0l, SEEK_END);
  608.     file_size = ftell(ctx->ifp);
  609.     ctx->frame_size = ctx->width * ctx->height * 3 / 2;
  610.  
  611.     if ((file_size < ctx->frame_size) ||
  612.         (file_size % ctx->frame_size)) {
  613.         fprintf(stderr, "The input file size %ld isn't a multiple of the frame size %d\n", file_size, ctx->frame_size);
  614.         goto err_exit;
  615.     }
  616.  
  617.     ctx->num_pictures = file_size / ctx->frame_size;
  618.     fseek(ctx->ifp, 0l, SEEK_SET);
  619.    
  620.     ctx->ofp = fopen(argv[4], "wb");
  621.    
  622.     if (ctx->ofp == NULL) {
  623.         fprintf(stderr, "Can't create the output file\n");
  624.         goto err_exit;
  625.     }
  626.  
  627.     opterr = 0;
  628.     ctx->fps = 30;
  629.     ctx->qp = 8;
  630.     ctx->rate_control_mode = VA_RC_CQP;
  631.     ctx->mode = MPEG2_MODE_IP;
  632.     ctx->profile = VAProfileMPEG2Main;
  633.     ctx->level = MPEG2_LEVEL_MAIN;
  634.  
  635.     optind = 5;
  636.  
  637.     while((c = getopt_long(argc, argv,
  638.                            "",
  639.                            long_options,
  640.                            &option_index)) != -1) {
  641.         switch(c) {
  642.         case 'c':
  643.             tmp = atoi(optarg);
  644.  
  645.             /* only support q_scale_type = 0 */
  646.             if (tmp > 62 || tmp < 2) {
  647.                 fprintf(stderr, "Warning: QP must be in [2, 62]\n");
  648.  
  649.                 if (tmp > 62)
  650.                     tmp = 62;
  651.  
  652.                 if (tmp < 2)
  653.                     tmp = 2;
  654.             }
  655.  
  656.             ctx->qp = tmp & 0xFE;
  657.             ctx->rate_control_mode = VA_RC_CQP;
  658.  
  659.             break;
  660.  
  661.         case 'f':
  662.             tmp = atoi(optarg);
  663.  
  664.             if (tmp <= 0)
  665.                 fprintf(stderr, "Warning: FPS must be greater than 0\n");
  666.             else
  667.                 ctx->fps = tmp;
  668.  
  669.             ctx->rate_control_mode = VA_RC_CBR;
  670.  
  671.             break;
  672.  
  673.         case 'm':
  674.             tmp = atoi(optarg);
  675.            
  676.             if (tmp < MPEG2_MODE_I || tmp > MPEG2_MODE_IPB)
  677.                 fprintf(stderr, "Waning: MODE must be 0, 1, or 2\n");
  678.             else
  679.                 ctx->mode = tmp;
  680.  
  681.             break;
  682.  
  683.         case 'p':
  684.             tmp = atoi(optarg);
  685.            
  686.             if (tmp < 0 || tmp > 1)
  687.                 fprintf(stderr, "Waning: PROFILE must be 0 or 1\n");
  688.             else
  689.                 profile = tmp;
  690.  
  691.             break;
  692.  
  693.         case 'l':
  694.             tmp = atoi(optarg);
  695.            
  696.             if (tmp < MPEG2_LEVEL_LOW || tmp > MPEG2_LEVEL_HIGH)
  697.                 fprintf(stderr, "Waning: LEVEL must be 0, 1, or 2\n");
  698.             else
  699.                 level = tmp;
  700.  
  701.             break;
  702.  
  703.         case '?':
  704.             fprintf(stderr, "Error: unkown command options\n");
  705.  
  706.         case 'h':
  707.             goto print_usage;
  708.         }
  709.     }
  710.  
  711.     mpeg2_profile_level(ctx, profile, level);
  712.  
  713.     return;
  714.  
  715. print_usage:    
  716.     usage(argv[0]);
  717. err_exit:
  718.     mpeg2enc_exit(ctx, 1);
  719. }
  720.  
  721. /*
  722.  * init
  723.  */
  724. void
  725. mpeg2enc_init_sequence_parameter(struct mpeg2enc_context *ctx,
  726.                                 VAEncSequenceParameterBufferMPEG2 *seq_param)
  727. {
  728.     int profile = 4, level = 8;
  729.  
  730.     switch (ctx->profile) {
  731.     case VAProfileMPEG2Simple:
  732.         profile = 5;
  733.         break;
  734.  
  735.     case VAProfileMPEG2Main:
  736.         profile = 4;
  737.         break;
  738.  
  739.     default:
  740.         assert(0);
  741.         break;
  742.     }
  743.  
  744.     switch (ctx->level) {
  745.     case MPEG2_LEVEL_LOW:
  746.         level = 10;
  747.         break;
  748.  
  749.     case MPEG2_LEVEL_MAIN:
  750.         level = 8;
  751.         break;
  752.  
  753.     case MPEG2_LEVEL_HIGH:
  754.         level = 4;
  755.         break;
  756.  
  757.     default:
  758.         assert(0);
  759.         break;
  760.     }
  761.        
  762.     seq_param->intra_period = ctx->intra_period;
  763.     seq_param->ip_period = ctx->ip_period;   /* FIXME: ??? */
  764.     seq_param->picture_width = ctx->width;
  765.     seq_param->picture_height = ctx->height;
  766.  
  767.     if (ctx->bit_rate > 0)
  768.         seq_param->bits_per_second = 1024 * ctx->bit_rate; /* use kbps as input */
  769.     else
  770.         seq_param->bits_per_second = 0x3FFFF * 400;
  771.  
  772.     seq_param->frame_rate = ctx->fps;
  773.     seq_param->aspect_ratio_information = 1;
  774.     seq_param->vbv_buffer_size = 3; /* B = 16 * 1024 * vbv_buffer_size */
  775.  
  776.     seq_param->sequence_extension.bits.profile_and_level_indication = profile << 4 | level;
  777.     seq_param->sequence_extension.bits.progressive_sequence = 1; /* progressive frame-pictures */
  778.     seq_param->sequence_extension.bits.chroma_format = CHROMA_FORMAT_420; /* 4:2:0 */
  779.     seq_param->sequence_extension.bits.low_delay = 0; /* FIXME */
  780.     seq_param->sequence_extension.bits.frame_rate_extension_n = 0;
  781.     seq_param->sequence_extension.bits.frame_rate_extension_d = 0;
  782.  
  783.     seq_param->gop_header.bits.time_code = (1 << 12); /* bit12: marker_bit */
  784.     seq_param->gop_header.bits.closed_gop = 0;
  785.     seq_param->gop_header.bits.broken_link = 0;    
  786. }
  787.  
  788. static void
  789. mpeg2enc_init_picture_parameter(struct mpeg2enc_context *ctx,
  790.                                VAEncPictureParameterBufferMPEG2 *pic_param)
  791. {
  792.     pic_param->forward_reference_picture = VA_INVALID_ID;
  793.     pic_param->backward_reference_picture = VA_INVALID_ID;
  794.     pic_param->reconstructed_picture = VA_INVALID_ID;
  795.     pic_param->coded_buf = VA_INVALID_ID;
  796.     pic_param->picture_type = VAEncPictureTypeIntra;
  797.  
  798.     pic_param->temporal_reference = 0;
  799.     pic_param->f_code[0][0] = 0xf;
  800.     pic_param->f_code[0][1] = 0xf;
  801.     pic_param->f_code[1][0] = 0xf;
  802.     pic_param->f_code[1][1] = 0xf;
  803.  
  804.     pic_param->picture_coding_extension.bits.intra_dc_precision = 0; /* 8bits */
  805.     pic_param->picture_coding_extension.bits.picture_structure = 3; /* frame picture */
  806.     pic_param->picture_coding_extension.bits.top_field_first = 0;
  807.     pic_param->picture_coding_extension.bits.frame_pred_frame_dct = 1; /* FIXME */
  808.     pic_param->picture_coding_extension.bits.concealment_motion_vectors = 0;
  809.     pic_param->picture_coding_extension.bits.q_scale_type = 0;
  810.     pic_param->picture_coding_extension.bits.intra_vlc_format = 0;
  811.     pic_param->picture_coding_extension.bits.alternate_scan = 0;
  812.     pic_param->picture_coding_extension.bits.repeat_first_field = 0;
  813.     pic_param->picture_coding_extension.bits.progressive_frame = 1;
  814.     pic_param->picture_coding_extension.bits.composite_display_flag = 0;
  815. }
  816.  
  817. static void
  818. mpeg2enc_alloc_va_resources(struct mpeg2enc_context *ctx)
  819. {
  820.     VAEntrypoint *entrypoint_list;
  821.     VAConfigAttrib attrib_list[2];
  822.     VAStatus va_status;
  823.     int max_entrypoints, num_entrypoints, entrypoint;
  824.     int major_ver, minor_ver;
  825.  
  826.     ctx->va_dpy = va_open_display();
  827.     va_status = vaInitialize(ctx->va_dpy,
  828.                              &major_ver,
  829.                              &minor_ver);
  830.     CHECK_VASTATUS(va_status, "vaInitialize");
  831.  
  832.     max_entrypoints = vaMaxNumEntrypoints(ctx->va_dpy);
  833.     entrypoint_list = malloc(max_entrypoints * sizeof(VAEntrypoint));
  834.     vaQueryConfigEntrypoints(ctx->va_dpy,
  835.                              ctx->profile,
  836.                              entrypoint_list,
  837.                              &num_entrypoints);
  838.  
  839.     for (entrypoint = 0; entrypoint < num_entrypoints; entrypoint++) {
  840.         if (entrypoint_list[entrypoint] == VAEntrypointEncSlice)
  841.             break;
  842.     }
  843.  
  844.     free(entrypoint_list);
  845.  
  846.     if (entrypoint == num_entrypoints) {
  847.         /* not find Slice entry point */
  848.         assert(0);
  849.     }
  850.  
  851.     /* find out the format for the render target, and rate control mode */
  852.     attrib_list[0].type = VAConfigAttribRTFormat;
  853.     attrib_list[1].type = VAConfigAttribRateControl;
  854.     vaGetConfigAttributes(ctx->va_dpy,
  855.                           ctx->profile,
  856.                           VAEntrypointEncSlice,
  857.                           &attrib_list[0],
  858.                           2);
  859.  
  860.     if ((attrib_list[0].value & VA_RT_FORMAT_YUV420) == 0) {
  861.         /* not find desired YUV420 RT format */
  862.         assert(0);
  863.     }
  864.  
  865.     if ((attrib_list[1].value & ctx->rate_control_mode) == 0) {
  866.         /* Can't find matched RC mode */
  867.         fprintf(stderr, "RC mode %d isn't found, exit\n", ctx->rate_control_mode);
  868.         assert(0);
  869.     }
  870.  
  871.     attrib_list[0].value = VA_RT_FORMAT_YUV420; /* set to desired RT format */
  872.     attrib_list[1].value = ctx->rate_control_mode; /* set to desired RC mode */
  873.  
  874.     va_status = vaCreateConfig(ctx->va_dpy,
  875.                                ctx->profile,
  876.                                VAEntrypointEncSlice,
  877.                                attrib_list,
  878.                                2,
  879.                                &ctx->config_id);
  880.     CHECK_VASTATUS(va_status, "vaCreateConfig");
  881.  
  882.     /* Create a context for this decode pipe */
  883.     va_status = vaCreateContext(ctx->va_dpy,
  884.                                 ctx->config_id,
  885.                                 ctx->width,
  886.                                 ctx->height,
  887.                                 VA_PROGRESSIVE,
  888.                                 0,
  889.                                 0,
  890.                                 &ctx->context_id);
  891.     CHECK_VASTATUS(va_status, "vaCreateContext");
  892.  
  893.     va_status = vaCreateSurfaces(ctx->va_dpy,
  894.                                  VA_RT_FORMAT_YUV420,
  895.                                  ctx->width,
  896.                                  ctx->height,
  897.                                  surface_ids,
  898.                                  SID_NUMBER,
  899.                                  NULL,
  900.                                  0);
  901.     CHECK_VASTATUS(va_status, "vaCreateSurfaces");
  902. }
  903.  
  904. static void
  905. mpeg2enc_init(struct mpeg2enc_context *ctx)
  906. {
  907.     int i;
  908.  
  909.     ctx->frame_data_buffer = (unsigned char *)malloc(ctx->frame_size);
  910.     ctx->seq_param_buf_id = VA_INVALID_ID;
  911.     ctx->pic_param_buf_id = VA_INVALID_ID;
  912.     ctx->packed_seq_header_param_buf_id = VA_INVALID_ID;
  913.     ctx->packed_seq_buf_id = VA_INVALID_ID;
  914.     ctx->packed_pic_header_param_buf_id = VA_INVALID_ID;
  915.     ctx->packed_pic_buf_id = VA_INVALID_ID;
  916.     ctx->codedbuf_buf_id = VA_INVALID_ID;
  917.     ctx->codedbuf_i_size = ctx->frame_size;
  918.     ctx->codedbuf_pb_size = 0;
  919.     ctx->next_display_order = 0;
  920.     ctx->next_type = VAEncPictureTypeIntra;
  921.  
  922.     if (ctx->mode == MPEG2_MODE_I) {
  923.         ctx->intra_period = 1;
  924.         ctx->ip_period = 0;
  925.     } else if (ctx->mode == MPEG2_MODE_IP) {
  926.         ctx->intra_period = 16;
  927.         ctx->ip_period = 0;
  928.     } else {
  929.         ctx->intra_period = 16;
  930.         ctx->ip_period = 2;
  931.     }
  932.  
  933.     ctx->next_bframes = ctx->ip_period;
  934.  
  935.     ctx->new_sequence = 1;
  936.     ctx->new_gop_header = 1;
  937.     ctx->gop_header_in_display_order = 0;
  938.  
  939.     ctx->bit_rate = -1;
  940.  
  941.     for (i = 0; i < MAX_SLICES; i++) {
  942.         ctx->slice_param_buf_id[i] = VA_INVALID_ID;
  943.     }
  944.  
  945.     mpeg2enc_init_sequence_parameter(ctx, &ctx->seq_param);
  946.     mpeg2enc_init_picture_parameter(ctx, &ctx->pic_param);
  947.     mpeg2enc_alloc_va_resources(ctx);
  948.  
  949.     /* thread */
  950.     ctx->current_input_surface = SID_INPUT_PICTURE_0;
  951.     ctx->current_upload_surface = SID_INPUT_PICTURE_1;
  952.     ctx->upload_thread_value = pthread_create(&ctx->upload_thread_id,
  953.                                               NULL,
  954.                                               upload_yuv_to_surface,
  955.                                               ctx);
  956. }
  957.  
  958. static int
  959. mpeg2enc_time_code(VAEncSequenceParameterBufferMPEG2 *seq_param,
  960.                    int num_frames)
  961. {
  962.     int fps = (int)(seq_param->frame_rate + 0.5);
  963.     int time_code = 0;
  964.     int time_code_pictures, time_code_seconds, time_code_minutes, time_code_hours;
  965.     int drop_frame_flag = 0;
  966.  
  967.     assert(fps <= 60);
  968.  
  969.     time_code_seconds = num_frames / fps;
  970.     time_code_pictures = num_frames % fps;
  971.     time_code |= time_code_pictures;
  972.  
  973.     time_code_minutes = time_code_seconds / 60;
  974.     time_code_seconds = time_code_seconds % 60;
  975.     time_code |= (time_code_seconds << 6);
  976.  
  977.     time_code_hours = time_code_minutes / 60;
  978.     time_code_minutes = time_code_minutes % 60;
  979.  
  980.     time_code |= (1 << 12);     /* marker_bit */
  981.     time_code |= (time_code_minutes << 13);
  982.  
  983.     time_code_hours = time_code_hours % 24;
  984.     time_code |= (time_code_hours << 19);
  985.  
  986.     time_code |= (drop_frame_flag << 24);
  987.  
  988.     return time_code;
  989. }
  990.  
  991. /*
  992.  * run
  993.  */
  994. static void
  995. mpeg2enc_update_sequence_parameter(struct mpeg2enc_context *ctx,
  996.                                    VAEncPictureType picture_type,
  997.                                    int coded_order,
  998.                                    int display_order)
  999. {
  1000.     VAEncSequenceParameterBufferMPEG2 *seq_param = &ctx->seq_param;
  1001.  
  1002.     /* update the time_code info for the new GOP */
  1003.     if (ctx->new_gop_header) {
  1004.         seq_param->gop_header.bits.time_code = mpeg2enc_time_code(seq_param, display_order);
  1005.     }
  1006. }
  1007.  
  1008. static void
  1009. mpeg2enc_update_picture_parameter(struct mpeg2enc_context *ctx,
  1010.                                   VAEncPictureType picture_type,
  1011.                                   int coded_order,
  1012.                                   int display_order)
  1013. {
  1014.     VAEncPictureParameterBufferMPEG2 *pic_param = &ctx->pic_param;
  1015.     uint8_t f_code_x, f_code_y;
  1016.  
  1017.     pic_param->picture_type = picture_type;
  1018.     pic_param->temporal_reference = (display_order - ctx->gop_header_in_display_order) & 0x3FF;
  1019.     pic_param->reconstructed_picture = surface_ids[SID_RECON_PICTURE];
  1020.     pic_param->forward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L0];
  1021.     pic_param->backward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L1];
  1022.  
  1023.     f_code_x = 0xf;
  1024.     f_code_y = 0xf;
  1025.     if (pic_param->picture_type != VAEncPictureTypeIntra) {
  1026.         if (ctx->level == MPEG2_LEVEL_LOW) {
  1027.                 f_code_x = 7;
  1028.                 f_code_y = 4;
  1029.         } else if (ctx->level == MPEG2_LEVEL_MAIN) {
  1030.                 f_code_x = 8;
  1031.                 f_code_y = 5;
  1032.         } else {
  1033.                 f_code_x = 9;
  1034.                 f_code_y = 5;
  1035.         }
  1036.     }
  1037.    
  1038.     if (pic_param->picture_type == VAEncPictureTypeIntra) {
  1039.         pic_param->f_code[0][0] = 0xf;
  1040.         pic_param->f_code[0][1] = 0xf;
  1041.         pic_param->f_code[1][0] = 0xf;
  1042.         pic_param->f_code[1][1] = 0xf;
  1043.         pic_param->forward_reference_picture = VA_INVALID_SURFACE;
  1044.         pic_param->backward_reference_picture = VA_INVALID_SURFACE;
  1045.  
  1046.     } else if (pic_param->picture_type == VAEncPictureTypePredictive) {
  1047.         pic_param->f_code[0][0] = f_code_x;
  1048.         pic_param->f_code[0][1] = f_code_y;
  1049.         pic_param->f_code[1][0] = 0xf;
  1050.         pic_param->f_code[1][1] = 0xf;
  1051.         pic_param->forward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L0];
  1052.         pic_param->backward_reference_picture = VA_INVALID_SURFACE;
  1053.     } else if (pic_param->picture_type == VAEncPictureTypeBidirectional) {
  1054.         pic_param->f_code[0][0] = f_code_x;
  1055.         pic_param->f_code[0][1] = f_code_y;
  1056.         pic_param->f_code[1][0] = f_code_x;
  1057.         pic_param->f_code[1][1] = f_code_y;
  1058.         pic_param->forward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L0];
  1059.         pic_param->backward_reference_picture = surface_ids[SID_REFERENCE_PICTURE_L1];
  1060.     } else {
  1061.         assert(0);
  1062.     }
  1063. }
  1064.  
  1065. static void
  1066. mpeg2enc_update_picture_parameter_buffer(struct mpeg2enc_context *ctx,
  1067.                                          VAEncPictureType picture_type,
  1068.                                          int coded_order,
  1069.                                          int display_order)
  1070. {
  1071.     VAEncPictureParameterBufferMPEG2 *pic_param = &ctx->pic_param;
  1072.     VAStatus va_status;
  1073.  
  1074.     /* update the coded buffer id */
  1075.     pic_param->coded_buf = ctx->codedbuf_buf_id;
  1076.     va_status = vaCreateBuffer(ctx->va_dpy,
  1077.                                ctx->context_id,
  1078.                                VAEncPictureParameterBufferType,
  1079.                                sizeof(*pic_param),
  1080.                                1,
  1081.                                pic_param,
  1082.                                &ctx->pic_param_buf_id);
  1083.     CHECK_VASTATUS(va_status, "vaCreateBuffer");
  1084. }
  1085.  
  1086. static void
  1087. mpeg2enc_update_slice_parameter(struct mpeg2enc_context *ctx, VAEncPictureType picture_type)
  1088. {
  1089.     VAEncSequenceParameterBufferMPEG2 *seq_param;
  1090.     VAEncPictureParameterBufferMPEG2 *pic_param;
  1091.     VAEncSliceParameterBufferMPEG2 *slice_param;
  1092.     VAStatus va_status;
  1093.     int i, width_in_mbs, height_in_mbs;
  1094.  
  1095.     pic_param = &ctx->pic_param;
  1096.     assert(pic_param->picture_coding_extension.bits.q_scale_type == 0);
  1097.  
  1098.     seq_param = &ctx->seq_param;
  1099.     width_in_mbs = (seq_param->picture_width + 15) / 16;
  1100.     height_in_mbs = (seq_param->picture_height + 15) / 16;
  1101.     ctx->num_slice_groups = 1;
  1102.  
  1103.     for (i = 0; i < height_in_mbs; i++) {
  1104.         slice_param = &ctx->slice_param[i];
  1105.         slice_param->macroblock_address = i * width_in_mbs;
  1106.         slice_param->num_macroblocks = width_in_mbs;
  1107.         slice_param->is_intra_slice = (picture_type == VAEncPictureTypeIntra);
  1108.         slice_param->quantiser_scale_code = ctx->qp / 2;
  1109.     }
  1110.  
  1111.     va_status = vaCreateBuffer(ctx->va_dpy,
  1112.                                ctx->context_id,
  1113.                                VAEncSliceParameterBufferType,
  1114.                                sizeof(*slice_param),
  1115.                                height_in_mbs,
  1116.                                ctx->slice_param,
  1117.                                ctx->slice_param_buf_id);
  1118.     CHECK_VASTATUS(va_status, "vaCreateBuffer");;
  1119. }
  1120.  
  1121. static int
  1122. begin_picture(struct mpeg2enc_context *ctx,
  1123.               int coded_order,
  1124.               int display_order,
  1125.               VAEncPictureType picture_type)
  1126. {
  1127.     VAStatus va_status;
  1128.     int tmp;
  1129.     VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
  1130.     unsigned int length_in_bits;
  1131.     unsigned char *packed_seq_buffer = NULL, *packed_pic_buffer = NULL;
  1132.  
  1133.     if (ctx->upload_thread_value != 0) {
  1134.         fprintf(stderr, "FATAL error!!!\n");
  1135.         exit(1);
  1136.     }
  1137.    
  1138.     pthread_join(ctx->upload_thread_id, NULL);
  1139.  
  1140.     ctx->upload_thread_value = -1;
  1141.     tmp = ctx->current_input_surface;
  1142.     ctx->current_input_surface = ctx->current_upload_surface;
  1143.     ctx->current_upload_surface = tmp;
  1144.  
  1145.     mpeg2enc_update_sequence_parameter(ctx, picture_type, coded_order, display_order);
  1146.     mpeg2enc_update_picture_parameter(ctx, picture_type, coded_order, display_order);
  1147.  
  1148.     if (ctx->new_sequence || ctx->new_gop_header) {
  1149.         assert(picture_type == VAEncPictureTypeIntra);
  1150.         length_in_bits = build_packed_seq_buffer(ctx, &ctx->seq_param, &packed_seq_buffer);
  1151.         packed_header_param_buffer.type = VAEncPackedHeaderMPEG2_SPS;
  1152.         packed_header_param_buffer.has_emulation_bytes = 0;
  1153.         packed_header_param_buffer.bit_length = length_in_bits;
  1154.         va_status = vaCreateBuffer(ctx->va_dpy,
  1155.                                    ctx->context_id,
  1156.                                    VAEncPackedHeaderParameterBufferType,
  1157.                                    sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
  1158.                                    &ctx->packed_seq_header_param_buf_id);
  1159.         CHECK_VASTATUS(va_status,"vaCreateBuffer");
  1160.  
  1161.         va_status = vaCreateBuffer(ctx->va_dpy,
  1162.                                    ctx->context_id,
  1163.                                    VAEncPackedHeaderDataBufferType,
  1164.                                    (length_in_bits + 7) / 8, 1, packed_seq_buffer,
  1165.                                    &ctx->packed_seq_buf_id);
  1166.         CHECK_VASTATUS(va_status,"vaCreateBuffer");
  1167.  
  1168.         free(packed_seq_buffer);
  1169.     }
  1170.  
  1171.     length_in_bits = build_packed_pic_buffer(&ctx->seq_param, &ctx->pic_param, &packed_pic_buffer);
  1172.     packed_header_param_buffer.type = VAEncPackedHeaderMPEG2_PPS;
  1173.     packed_header_param_buffer.has_emulation_bytes = 0;
  1174.     packed_header_param_buffer.bit_length = length_in_bits;
  1175.  
  1176.     va_status = vaCreateBuffer(ctx->va_dpy,
  1177.                                ctx->context_id,
  1178.                                VAEncPackedHeaderParameterBufferType,
  1179.                                sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
  1180.                                &ctx->packed_pic_header_param_buf_id);
  1181.     CHECK_VASTATUS(va_status,"vaCreateBuffer");
  1182.  
  1183.     va_status = vaCreateBuffer(ctx->va_dpy,
  1184.                                ctx->context_id,
  1185.                                VAEncPackedHeaderDataBufferType,
  1186.                                (length_in_bits + 7) / 8, 1, packed_pic_buffer,
  1187.                                &ctx->packed_pic_buf_id);
  1188.     CHECK_VASTATUS(va_status,"vaCreateBuffer");
  1189.  
  1190.     free(packed_pic_buffer);
  1191.  
  1192.     /* sequence parameter set */
  1193.     VAEncSequenceParameterBufferMPEG2 *seq_param = &ctx->seq_param;
  1194.     va_status = vaCreateBuffer(ctx->va_dpy,
  1195.                                ctx->context_id,
  1196.                                VAEncSequenceParameterBufferType,
  1197.                                sizeof(*seq_param),
  1198.                                1,
  1199.                                seq_param,
  1200.                                &ctx->seq_param_buf_id);
  1201.     CHECK_VASTATUS(va_status,"vaCreateBuffer");;
  1202.  
  1203.     /* slice parameter */
  1204.     mpeg2enc_update_slice_parameter(ctx, picture_type);
  1205.  
  1206.     return 0;
  1207. }
  1208.  
  1209. static int
  1210. mpeg2enc_render_picture(struct mpeg2enc_context *ctx)
  1211. {
  1212.     VAStatus va_status;
  1213.     VABufferID va_buffers[16];
  1214.     unsigned int num_va_buffers = 0;
  1215.  
  1216.     va_buffers[num_va_buffers++] = ctx->seq_param_buf_id;
  1217.     va_buffers[num_va_buffers++] = ctx->pic_param_buf_id;
  1218.  
  1219.     if (ctx->packed_seq_header_param_buf_id != VA_INVALID_ID)
  1220.         va_buffers[num_va_buffers++] = ctx->packed_seq_header_param_buf_id;
  1221.  
  1222.     if (ctx->packed_seq_buf_id != VA_INVALID_ID)
  1223.         va_buffers[num_va_buffers++] = ctx->packed_seq_buf_id;
  1224.  
  1225.     if (ctx->packed_pic_header_param_buf_id != VA_INVALID_ID)
  1226.         va_buffers[num_va_buffers++] = ctx->packed_pic_header_param_buf_id;
  1227.  
  1228.     if (ctx->packed_pic_buf_id != VA_INVALID_ID)
  1229.         va_buffers[num_va_buffers++] = ctx->packed_pic_buf_id;
  1230.  
  1231.     va_status = vaBeginPicture(ctx->va_dpy,
  1232.                                ctx->context_id,
  1233.                                surface_ids[ctx->current_input_surface]);
  1234.     CHECK_VASTATUS(va_status,"vaBeginPicture");
  1235.  
  1236.     va_status = vaRenderPicture(ctx->va_dpy,
  1237.                                 ctx->context_id,
  1238.                                 va_buffers,
  1239.                                 num_va_buffers);
  1240.     CHECK_VASTATUS(va_status,"vaRenderPicture");
  1241.  
  1242.     va_status = vaRenderPicture(ctx->va_dpy,
  1243.                                 ctx->context_id,
  1244.                                 &ctx->slice_param_buf_id[0],
  1245.                                 ctx->num_slice_groups);
  1246.     CHECK_VASTATUS(va_status,"vaRenderPicture");
  1247.  
  1248.     va_status = vaEndPicture(ctx->va_dpy, ctx->context_id);
  1249.     CHECK_VASTATUS(va_status,"vaEndPicture");
  1250.  
  1251.     return 0;
  1252. }
  1253.  
  1254. static int
  1255. mpeg2enc_destroy_buffers(struct mpeg2enc_context *ctx, VABufferID *va_buffers, unsigned int num_va_buffers)
  1256. {
  1257.     VAStatus va_status;
  1258.     unsigned int i;
  1259.  
  1260.     for (i = 0; i < num_va_buffers; i++) {
  1261.         if (va_buffers[i] != VA_INVALID_ID) {
  1262.             va_status = vaDestroyBuffer(ctx->va_dpy, va_buffers[i]);
  1263.             CHECK_VASTATUS(va_status,"vaDestroyBuffer");
  1264.             va_buffers[i] = VA_INVALID_ID;
  1265.         }
  1266.     }
  1267.  
  1268.     return 0;
  1269. }
  1270.  
  1271. static void
  1272. end_picture(struct mpeg2enc_context *ctx, VAEncPictureType picture_type, int next_is_bpic)
  1273. {
  1274.     VABufferID tempID;
  1275.  
  1276.     /* Prepare for next picture */
  1277.     tempID = surface_ids[SID_RECON_PICTURE];  
  1278.  
  1279.     if (picture_type != VAEncPictureTypeBidirectional) {
  1280.         if (next_is_bpic) {
  1281.             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L1];
  1282.             surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;    
  1283.         } else {
  1284.             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0];
  1285.             surface_ids[SID_REFERENCE_PICTURE_L0] = tempID;
  1286.         }
  1287.     } else {
  1288.         if (!next_is_bpic) {
  1289.             surface_ids[SID_RECON_PICTURE] = surface_ids[SID_REFERENCE_PICTURE_L0];
  1290.             surface_ids[SID_REFERENCE_PICTURE_L0] = surface_ids[SID_REFERENCE_PICTURE_L1];
  1291.             surface_ids[SID_REFERENCE_PICTURE_L1] = tempID;
  1292.         }
  1293.     }
  1294.  
  1295.     mpeg2enc_destroy_buffers(ctx, &ctx->seq_param_buf_id, 1);
  1296.     mpeg2enc_destroy_buffers(ctx, &ctx->pic_param_buf_id, 1);
  1297.     mpeg2enc_destroy_buffers(ctx, &ctx->packed_seq_header_param_buf_id, 1);
  1298.     mpeg2enc_destroy_buffers(ctx, &ctx->packed_seq_buf_id, 1);
  1299.     mpeg2enc_destroy_buffers(ctx, &ctx->packed_pic_header_param_buf_id, 1);
  1300.     mpeg2enc_destroy_buffers(ctx, &ctx->packed_pic_buf_id, 1);
  1301.     mpeg2enc_destroy_buffers(ctx, &ctx->slice_param_buf_id[0], ctx->num_slice_groups);
  1302.     mpeg2enc_destroy_buffers(ctx, &ctx->codedbuf_buf_id, 1);
  1303.     memset(ctx->slice_param, 0, sizeof(ctx->slice_param));
  1304.     ctx->num_slice_groups = 0;
  1305. }
  1306.  
  1307. static int
  1308. store_coded_buffer(struct mpeg2enc_context *ctx, VAEncPictureType picture_type)
  1309. {
  1310.     VACodedBufferSegment *coded_buffer_segment;
  1311.     unsigned char *coded_mem;
  1312.     int slice_data_length;
  1313.     VAStatus va_status;
  1314.     VASurfaceStatus surface_status;
  1315.     size_t w_items;
  1316.  
  1317.     va_status = vaSyncSurface(ctx->va_dpy, surface_ids[ctx->current_input_surface]);
  1318.     CHECK_VASTATUS(va_status,"vaSyncSurface");
  1319.  
  1320.     surface_status = 0;
  1321.     va_status = vaQuerySurfaceStatus(ctx->va_dpy, surface_ids[ctx->current_input_surface], &surface_status);
  1322.     CHECK_VASTATUS(va_status,"vaQuerySurfaceStatus");
  1323.  
  1324.     va_status = vaMapBuffer(ctx->va_dpy, ctx->codedbuf_buf_id, (void **)(&coded_buffer_segment));
  1325.     CHECK_VASTATUS(va_status,"vaMapBuffer");
  1326.     coded_mem = coded_buffer_segment->buf;
  1327.  
  1328.     if (coded_buffer_segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
  1329.         if (picture_type == VAEncPictureTypeIntra)
  1330.             ctx->codedbuf_i_size *= 2;
  1331.         else
  1332.             ctx->codedbuf_pb_size *= 2;
  1333.  
  1334.         vaUnmapBuffer(ctx->va_dpy, ctx->codedbuf_buf_id);
  1335.         return -1;
  1336.     }
  1337.  
  1338.     slice_data_length = coded_buffer_segment->size;
  1339.  
  1340.     do {
  1341.         w_items = fwrite(coded_mem, slice_data_length, 1, ctx->ofp);
  1342.     } while (w_items != 1);
  1343.  
  1344.     if (picture_type == VAEncPictureTypeIntra) {
  1345.         if (ctx->codedbuf_i_size > slice_data_length * 3 / 2) {
  1346.             ctx->codedbuf_i_size = slice_data_length * 3 / 2;
  1347.         }
  1348.        
  1349.         if (ctx->codedbuf_pb_size < slice_data_length) {
  1350.             ctx->codedbuf_pb_size = slice_data_length;
  1351.         }
  1352.     } else {
  1353.         if (ctx->codedbuf_pb_size > slice_data_length * 3 / 2) {
  1354.             ctx->codedbuf_pb_size = slice_data_length * 3 / 2;
  1355.         }
  1356.     }
  1357.  
  1358.     vaUnmapBuffer(ctx->va_dpy, ctx->codedbuf_buf_id);
  1359.  
  1360.     return 0;
  1361. }
  1362.  
  1363. static void
  1364. encode_picture(struct mpeg2enc_context *ctx,
  1365.                int coded_order,
  1366.                int display_order,
  1367.                VAEncPictureType picture_type,
  1368.                int next_is_bpic,
  1369.                int next_display_order)
  1370. {
  1371.     VAStatus va_status;
  1372.     int ret = 0, codedbuf_size;
  1373.    
  1374.     begin_picture(ctx, coded_order, display_order, picture_type);
  1375.  
  1376.     if (1) {
  1377.         /* upload YUV data to VA surface for next frame */
  1378.         if (next_display_order >= ctx->num_pictures)
  1379.             next_display_order = ctx->num_pictures - 1;
  1380.  
  1381.         fseek(ctx->ifp, ctx->frame_size * next_display_order, SEEK_SET);
  1382.         ctx->upload_thread_value = pthread_create(&ctx->upload_thread_id,
  1383.                                                   NULL,
  1384.                                                   upload_yuv_to_surface,
  1385.                                                   ctx);
  1386.     }
  1387.  
  1388.     do {
  1389.         mpeg2enc_destroy_buffers(ctx, &ctx->codedbuf_buf_id, 1);
  1390.         mpeg2enc_destroy_buffers(ctx, &ctx->pic_param_buf_id, 1);
  1391.  
  1392.  
  1393.         if (VAEncPictureTypeIntra == picture_type) {
  1394.             codedbuf_size = ctx->codedbuf_i_size;
  1395.         } else {
  1396.             codedbuf_size = ctx->codedbuf_pb_size;
  1397.         }
  1398.  
  1399.         /* coded buffer */
  1400.         va_status = vaCreateBuffer(ctx->va_dpy,
  1401.                                    ctx->context_id,
  1402.                                    VAEncCodedBufferType,
  1403.                                    codedbuf_size, 1, NULL,
  1404.                                    &ctx->codedbuf_buf_id);
  1405.         CHECK_VASTATUS(va_status,"vaCreateBuffer");
  1406.  
  1407.         /* picture parameter set */
  1408.         mpeg2enc_update_picture_parameter_buffer(ctx, picture_type, coded_order, display_order);
  1409.  
  1410.         mpeg2enc_render_picture(ctx);
  1411.  
  1412.         ret = store_coded_buffer(ctx, picture_type);
  1413.     } while (ret);
  1414.  
  1415.     end_picture(ctx, picture_type, next_is_bpic);
  1416. }
  1417.  
  1418. static void
  1419. update_next_frame_info(struct mpeg2enc_context *ctx,
  1420.                        VAEncPictureType curr_type,
  1421.                        int curr_coded_order,
  1422.                        int curr_display_order)
  1423. {
  1424.     if (((curr_coded_order + 1) % ctx->intra_period) == 0) {
  1425.         ctx->next_type = VAEncPictureTypeIntra;
  1426.         ctx->next_display_order = curr_coded_order + 1;
  1427.        
  1428.         return;
  1429.     }
  1430.  
  1431.     if (curr_type == VAEncPictureTypeIntra) {
  1432.         assert(curr_display_order == curr_coded_order);
  1433.         ctx->next_type = VAEncPictureTypePredictive;
  1434.         ctx->next_bframes = ctx->ip_period;
  1435.         ctx->next_display_order = curr_display_order + ctx->next_bframes + 1;
  1436.     } else if (curr_type == VAEncPictureTypePredictive) {
  1437.         if (ctx->ip_period == 0) {
  1438.             assert(curr_display_order == curr_coded_order);
  1439.             ctx->next_type = VAEncPictureTypePredictive;
  1440.             ctx->next_display_order = curr_display_order + 1;
  1441.         } else {
  1442.             ctx->next_type = VAEncPictureTypeBidirectional;
  1443.             ctx->next_display_order = curr_display_order - ctx->next_bframes;
  1444.             ctx->next_bframes--;
  1445.         }
  1446.     } else if (curr_type == VAEncPictureTypeBidirectional) {
  1447.         if (ctx->next_bframes == 0) {
  1448.             ctx->next_type = VAEncPictureTypePredictive;
  1449.             ctx->next_bframes = ctx->ip_period;
  1450.             ctx->next_display_order = curr_display_order + ctx->next_bframes + 2;
  1451.         } else {
  1452.             ctx->next_type = VAEncPictureTypeBidirectional;
  1453.             ctx->next_display_order = curr_display_order + 1;
  1454.             ctx->next_bframes--;
  1455.         }
  1456.     }
  1457.  
  1458.     if (ctx->next_display_order >= ctx->num_pictures) {
  1459.         int rtmp = ctx->next_display_order - (ctx->num_pictures - 1);
  1460.         ctx->next_display_order = ctx->num_pictures - 1;
  1461.         ctx->next_bframes -= rtmp;
  1462.     }
  1463. }
  1464.  
  1465. static void
  1466. mpeg2enc_run(struct mpeg2enc_context *ctx)
  1467. {
  1468.     int display_order = 0, coded_order = 0;
  1469.     VAEncPictureType type;
  1470.  
  1471.     ctx->new_sequence = 1;
  1472.     ctx->new_gop_header = 1;
  1473.     ctx->gop_header_in_display_order = display_order;
  1474.  
  1475.     while (coded_order < ctx->num_pictures) {
  1476.         type = ctx->next_type;
  1477.         display_order = ctx->next_display_order;
  1478.         /* follow the IPBxxBPBxxB mode */
  1479.         update_next_frame_info(ctx, type, coded_order, display_order);
  1480.         encode_picture(ctx,
  1481.                        coded_order,
  1482.                        display_order,
  1483.                        type,
  1484.                        ctx->next_type == VAEncPictureTypeBidirectional,
  1485.                        ctx->next_display_order);
  1486.  
  1487.         /* update gop_header */
  1488.         ctx->new_sequence = 0;
  1489.         ctx->new_gop_header = ctx->next_type == VAEncPictureTypeIntra;
  1490.  
  1491.         if (ctx->new_gop_header)
  1492.             ctx->gop_header_in_display_order += ctx->intra_period;
  1493.  
  1494.         coded_order++;
  1495.  
  1496.         fprintf(stderr, "\r %d/%d ...", coded_order, ctx->num_pictures);
  1497.         fflush(stdout);
  1498.     }
  1499. }
  1500.  
  1501. /*
  1502.  * end
  1503.  */
  1504. static void
  1505. mpeg2enc_release_va_resources(struct mpeg2enc_context *ctx)
  1506. {
  1507.     vaDestroySurfaces(ctx->va_dpy, surface_ids, SID_NUMBER);   
  1508.     vaDestroyContext(ctx->va_dpy, ctx->context_id);
  1509.     vaDestroyConfig(ctx->va_dpy, ctx->config_id);
  1510.     vaTerminate(ctx->va_dpy);
  1511.     va_close_display(ctx->va_dpy);
  1512. }
  1513.  
  1514. static void
  1515. mpeg2enc_end(struct mpeg2enc_context *ctx)
  1516. {
  1517.     pthread_join(ctx->upload_thread_id, NULL);
  1518.     mpeg2enc_release_va_resources(ctx);
  1519. }
  1520.  
  1521. int
  1522. main(int argc, char *argv[])
  1523. {
  1524.     struct mpeg2enc_context ctx;
  1525.     struct timeval tpstart, tpend;
  1526.     float timeuse;
  1527.  
  1528.     gettimeofday(&tpstart, NULL);
  1529.  
  1530.     memset(&ctx, 0, sizeof(ctx));
  1531.     parse_args(&ctx, argc, argv);
  1532.     mpeg2enc_init(&ctx);
  1533.     mpeg2enc_run(&ctx);
  1534.     mpeg2enc_end(&ctx);
  1535.  
  1536.     gettimeofday(&tpend, NULL);
  1537.     timeuse = 1000000 * (tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec - tpstart.tv_usec;
  1538.     timeuse /= 1000000;
  1539.     fprintf(stderr, "\ndone!\n");
  1540.     fprintf(stderr, "encode %d frames in %f secondes, FPS is %.1f\n", ctx.num_pictures, timeuse, ctx.num_pictures / timeuse);
  1541.  
  1542.     mpeg2enc_exit(&ctx, 0);
  1543.  
  1544.     return 0;
  1545. }
  1546.