2012-02-14 67 views
5

Vì mục đích nghiên cứu, tôi đang cố gắng sửa đổi vectơ chuyển động H.264 (MV) cho mỗi khung P và B trước khi bù chuyển động trong quá trình giải mã. Tôi đang sử dụng FFmpeg cho mục đích này. Một ví dụ về sửa đổi sẽ thay thế từng MV với các láng giềng không gian ban đầu của nó và sau đó sử dụng các MV kết quả để bù trừ chuyển động, chứ không phải các bản gốc. Hãy hướng dẫn tôi một cách thích hợp.Sửa đổi vectơ chuyển động trong bộ giải mã H.264 ffmpeg

Cho đến giờ, tôi đã có thể thực hiện sửa đổi MV đơn giản trong tệp /libavcodec/h264_cavlc.c. Trong hàm, ff_h264_decode_mb_cavlc(), sửa đổi các biến số mxcủa tôi, bằng cách tăng giá trị của chúng sửa đổi MV được sử dụng trong khi giải mã.

Ví dụ như hình dưới đây, các mx giá trị của tôi được tăng lên 50, do đó kéo dài các MV được sử dụng trong các bộ giải mã.

mx += get_se_golomb(&s->gb)+50; 
my += get_se_golomb(&s->gb)+50; 

Tuy nhiên, trong vấn đề này, tôi không biết làm thế nào để truy cập vào những người hàng xóm của mxtôi cho không gian của tôi phân tích rằng tôi đã đề cập trong đoạn đầu tiên có ý nghĩa. Tôi tin rằng chìa khóa để làm như vậy nằm trong thao tác mảng, mv_cache.

Một thử nghiệm khác mà tôi đã thực hiện có trong tệp, libavcodec/error_resilience.c. Dựa trên hàm guess_mv(), tôi đã tạo hàm mới, mean_mv() được thực hiện trong ff_er_frame_end() trong câu lệnh if đầu tiên. Câu lệnh if đầu tiên đó thoát khỏi hàm ff_er_frame_end() nếu một trong các điều kiện là số lỗi không (s-> error_count == 0). Tuy nhiên, tôi quyết định chèn hàm mean_mv() vào thời điểm này để luôn luôn được thực hiện khi có số lỗi bằng 0. Thử nghiệm này phần nào mang lại kết quả tôi muốn vì tôi có thể bắt đầu thấy hiện vật ở phần trên cùng của video nhưng chúng bị hạn chế ở góc trên bên phải. Tôi đoán rằng chức năng chèn của tôi không được hoàn thành để đáp ứng thời hạn phát lại hoặc một cái gì đó.

Dưới đây là câu lệnh if đã được sửa đổi. Bổ sung duy nhất là chức năng của tôi, mean_mv (s).

if(!s->error_recognition || s->error_count==0 || s->avctx->lowres || 
     s->avctx->hwaccel || 
     s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU || 
     s->picture_structure != PICT_FRAME || // we dont support ER of field pictures yet, though it should not crash if enabled 
     s->error_count==3*s->mb_width*(s->avctx->skip_top + s->avctx->skip_bottom)) { 
     //av_log(s->avctx, AV_LOG_DEBUG, "ff_er_frame_end in er.c\n"); //KG 
     if(s->pict_type==AV_PICTURE_TYPE_P) 
      mean_mv(s); 
     return; 

Và đây là mean_mv() chức năng tôi tạo ra dựa trên guess_mv().

static void mean_mv(MpegEncContext *s){ 
    //uint8_t fixed[s->mb_stride * s->mb_height]; 
    //const int mb_stride = s->mb_stride; 
    const int mb_width = s->mb_width; 
    const int mb_height= s->mb_height; 
    int mb_x, mb_y, mot_step, mot_stride; 

    //av_log(s->avctx, AV_LOG_DEBUG, "mean_mv\n"); //KG 

    set_mv_strides(s, &mot_step, &mot_stride); 

    for(mb_y=0; mb_y<s->mb_height; mb_y++){ 
     for(mb_x=0; mb_x<s->mb_width; mb_x++){ 
      const int mb_xy= mb_x + mb_y*s->mb_stride; 
      const int mot_index= (mb_x + mb_y*mot_stride) * mot_step; 
      int mv_predictor[4][2]={{0}}; 
      int ref[4]={0}; 
      int pred_count=0; 
      int m, n; 

      if(IS_INTRA(s->current_picture.f.mb_type[mb_xy])) continue; 
      //if(!(s->error_status_table[mb_xy]&MV_ERROR)){ 
      //if (1){ 
      if(mb_x>0){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index - mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index - mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy-1)]; 
       pred_count++; 
      } 

      if(mb_x+1<mb_width){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index + mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index + mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy+1)]; 
       pred_count++; 
      } 

      if(mb_y>0){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index - mot_stride*mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index - mot_stride*mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy-s->mb_stride)]; 
       pred_count++; 
      } 

      if(mb_y+1<mb_height){ 
       mv_predictor[pred_count][0]= s->current_picture.f.motion_val[0][mot_index + mot_stride*mot_step][0]; 
       mv_predictor[pred_count][1]= s->current_picture.f.motion_val[0][mot_index + mot_stride*mot_step][1]; 
       ref   [pred_count] = s->current_picture.f.ref_index[0][4*(mb_xy+s->mb_stride)]; 
       pred_count++; 
      } 

      if(pred_count==0) continue; 

      if(pred_count>=1){ 
       int sum_x=0, sum_y=0, sum_r=0; 
       int k; 

       for(k=0; k<pred_count; k++){ 
        sum_x+= mv_predictor[k][0]; // Sum all the MVx from MVs avail. for EC 
        sum_y+= mv_predictor[k][1]; // Sum all the MVy from MVs avail. for EC 
        sum_r+= ref[k]; 
        // if(k && ref[k] != ref[k-1]) 
        // goto skip_mean_and_median; 
       } 

       mv_predictor[pred_count][0] = sum_x/k; 
       mv_predictor[pred_count][1] = sum_y/k; 
       ref   [pred_count] = sum_r/k; 
      } 

      s->mv[0][0][0] = mv_predictor[pred_count][0]; 
      s->mv[0][0][1] = mv_predictor[pred_count][1]; 

      for(m=0; m<mot_step; m++){ 
       for(n=0; n<mot_step; n++){ 
        s->current_picture.f.motion_val[0][mot_index + m + n * mot_stride][0] = s->mv[0][0][0]; 
        s->current_picture.f.motion_val[0][mot_index + m + n * mot_stride][1] = s->mv[0][0][1]; 
       } 
      } 

      decode_mb(s, ref[pred_count]); 

      //} 
     } 
    } 
} 

Tôi thực sự đánh giá cao một số trợ giúp về cách thực hiện điều này đúng cách.

Trả lời

2

Đã lâu rồi tôi không liên lạc được với mã của FFMPEG trong nội bộ.

Tuy nhiên, với kinh nghiệm của tôi với bên trong kinh dị FFMPEG (bạn sẽ biết những gì tôi có ý nghĩa), tôi thà cung cấp cho bạn một lời khuyên thực dụng đơn giản.

Đề xuất # 1
khả năng nhất là khi vector chuyển động của mỗi khối được xác định - bạn có thể tạo thêm mảng của riêng bên FFMPEG bối cảnh encoder (còn được gọi s) mà sẽ lưu trữ tất cả trong số họ. Khi thuật toán của bạn chạy nó sẽ nhận các giá trị từ đó.

Đề xuất # 2
Một điều tôi đọc (tôi không chắc chắn nếu tôi đọc nó đúng)

các mx và các giá trị của tôi được tăng 50

Tôi nghĩ 50 là một vector chuyển động lớn rất . Và thông thường, phạm vi giá trị F của mã hóa vector chuyển động sẽ bị giới hạn trước. Nếu bạn thay đổi mọi thứ bằng cách +/- 8 (hoặc thậm chí +/- 16) có thể chỉ là ok- nhưng +50 có thể cao đến nỗi kết quả cuối cùng có thể không phải là mã hóa mọi thứ đúng cách.

Tôi không hiểu rõ mục tiêu của bạn vềmean_mv()và bạn không mong đợi điều gì từ đó. Vui lòng cụm từ lại một chút.

+0

Cảm ơn bạn đã bình luận. Tôi sẽ xem xét đề xuất đầu tiên của bạn. Đối với đề nghị thứ hai của bạn, nó tương ứng với những phát hiện của tôi. Khi tôi đọc các giá trị vector chuyển động ('mx' và' my') trong 'h264_cavlc.c', tôi nhận được các giá trị cực lớn như 500. Điều đó là rất bất hợp lý trừ khi có một số tỷ lệ chuyển đổi như một hệ số 50 Nếu không, tôi không biết tại sao các giá trị vectơ chuyển động lớn như thế. – qontranami

+0

Đối với 'mean_mv()' xem xét một khung hình P. Hỗ trợ khung hình B sẽ được thêm vào sau. Khung P chứa macroblocks với các vector chuyển động (MV). Hãy để chúng tôi nhóm các MV đó trong một tập hợp gọi là 'a'. Bây giờ, công việc của 'mean_mv()' là tạo ra một bộ vector chuyển động mới, 'b', sẽ thay thế' a' thành tập hợp MV cuối cùng. Mỗi MV trong 'b' là phiên bản sửa đổi của MV tương ứng trong' a'. Một cách để sửa đổi một MV trong 'a' là lấy trung bình không gian của các MV xung quanh trong' a' và đặt kết quả vào 'b'. Bằng cách này, tôi có thể điều tra hiệu quả của trung bình không gian và các kỹ thuật khác để che giấu lỗi. – qontranami

+0

'mean_mv()' thực sự là một ý tưởng tuyệt vời. Điều này cũng có thể giúp đoán vector chuyển động toàn cầu (theo kiểu MPEG4-v2). Và cũng có thể, vì bạn biết chuyển động của cảnh trung bình, bạn có thể bắt đầu tất cả các dự đoán từ đó thay vì tan '(0,0)'. Tốt nhất của may mắn đào 'ffmpeg' –