5

ビットマップをフレームとして C\C++ の Ogg Theora に書き込む方法は?

ソース付きのいくつかの例は素晴らしいでしょう!)

4

2 に答える 2

9

ソリューション全体をコード サンプルとしてここに投稿するには少し長くなりますが、Xiph.org から libtheora をダウンロードすると、png2theora の例があります。これから言及するすべてのライブラリ関数は、theora と ogg に関する Xiph.org のドキュメントで見つけることができます。

  1. th_info_init() を呼び出して th_info 構造体を初期化し、適切なメンバーを割り当てて出力パラメータを設定します。
  2. その構造体を th_encode_alloc() の呼び出しで使用して、エンコーダー コンテキストを取得します。
  3. ogg_stream_init() で ogg ストリームを初期化します
  4. th_comment_init を使用して空の th_comment 構造体を初期化します

以下を繰り返します。

  1. エンコーダ コンテキスト、空白のコメント構造体、および ogg_packet を使用して th_encode_flushheader を呼び出します。
  2. 結果のパケットを ogg_stream_packetin() で ogg ストリームに送信します

th_encode_flushheader が 0 (またはエラー コード) を返すまで

ここで、ogg_stream_pageout() を繰り返し呼び出し、page.header、次に page.body を出力ファイルに書き込むたびに、0 が返されるまで繰り返します。次に、ogg_stream_flush を呼び出し、結果のページをファイルに書き込みます。

フレームをエンコーダーに書き込むことができるようになりました。これが私がやった方法です:

int theora_write_frame(int outputFd, unsigned long w, unsigned long h, unsigned char *yuv_y, unsigned char *yuv_u, unsigned char *yuv_v, int last)
{
  th_ycbcr_buffer ycbcr;
  ogg_packet op;
  ogg_page og;

  unsigned long yuv_w;
  unsigned long yuv_h;

  /* Must hold: yuv_w >= w */
  yuv_w = (w + 15) & ~15;
  /* Must hold: yuv_h >= h */
  yuv_h = (h + 15) & ~15;

  //Fill out the ycbcr buffer
  ycbcr[0].width = yuv_w;
  ycbcr[0].height = yuv_h;
  ycbcr[0].stride = yuv_w;
  ycbcr[1].width = yuv_w;
  ycbcr[1].stride = ycbcr[1].width;
  ycbcr[1].height = yuv_h;
  ycbcr[2].width = ycbcr[1].width;
  ycbcr[2].stride = ycbcr[1].stride;
  ycbcr[2].height = ycbcr[1].height;

  if(encoderInfo->pixel_fmt == TH_PF_420)
  {
    //Chroma is decimated by 2 in both directions
    ycbcr[1].width = yuv_w >> 1;
    ycbcr[2].width = yuv_w >> 1;
    ycbcr[1].height = yuv_h >> 1;
    ycbcr[2].height = yuv_h >> 1;
  }else if(encoderInfo->pixel_fmt == TH_PF_422)
  {
    ycbcr[1].width = yuv_w >> 1;
    ycbcr[2].width = yuv_w >> 1;
  }else if(encoderInfo->pixel_fmt != TH_PF_422)
  {
    //Then we have an unknown pixel format
    //We don't know how long the arrays are!
    fprintf(stderr, "[theora_write_frame] Unknown pixel format in writeFrame!\n");
    return -1;
  }

  ycbcr[0].data = yuv_y;
  ycbcr[1].data = yuv_u;
  ycbcr[2].data = yuv_v;

  /* Theora is a one-frame-in,one-frame-out system; submit a frame
     for compression and pull out the packet */
  if(th_encode_ycbcr_in(encoderContext, ycbcr)) {
    fprintf(stderr, "[theora_write_frame] Error: could not encode frame\n");
    return -1;
  }

  if(!th_encode_packetout(encoderContext, last, &op)) {
    fprintf(stderr, "[theora_write_frame] Error: could not read packets\n");
    return -1;
  }

  ogg_stream_packetin(&theoraStreamState, &op);
  ssize_t bytesWritten = 0;
  int pagesOut = 0;
  while(ogg_stream_pageout(&theoraStreamState, &og)) {
    pagesOut ++;
    bytesWritten = write(outputFd, og.header, og.header_len);
    if(bytesWritten != og.header_len)
    {
      fprintf(stderr, "[theora_write_frame] Error: Could not write to file\n");
      return -1;
    }
    bytesWritten = write(outputFd, og.body, og.body_len);
    if(bytesWritten != og.body_len)
    {
      bytesWritten = fprintf(stderr, "[theora_write_frame] Error: Could not write to file\n");
      return -1;
    }
  }
  return pagesOut;
}

ここで、encoderInfo は、エンコーダーの初期化に使用される th_info 構造体です (データ セクションでは静的です)。

最後のフレームで、最後のフレームを th_encode_packetout() に設定すると、ストリームが適切に終了するようになります。

完了したら、必ずクリーンアップしてください (主に fds を閉じます)。th_info_clear() は th_info 構造をクリアし、th_encode_free() はエンコーダ コンテキストを解放します。

明らかに、ビットマップを theora_write_frame() に渡す前に、ビットマップを YUV プレーンに変換する必要があります。

これが役立つことを願っています。幸運を!

于 2010-08-30T16:30:29.373 に答える
3

libtheora APIサンプル コードは次のとおりです。

これは、theora バイナリの使用方法を示すマイクロハウツーです。エンコーダーは生の圧縮されていないビデオの「yuv4mpeg」データを読み取るため、ビデオ フレームをエンコーダーにパイプすることで、アプリからもそれを使用できます。

于 2009-12-21T12:18:15.393 に答える