高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QTMCC19
Image Decompressor Data-loading Procs


Q: グラフィックスインポータとともに使うデコンプレッサコンポーネントを記述しており、すべてのイメージデータを伸張前に単一のバッファに読み込む必要があります。ImageCodecPreflight を実装する際に、bandMin を確かにイメージのフルハイトに設定しました。しかし、ImageCodecBeginBand に渡されたバッファサイズは 32K に設定されており、ディスク上のイメージのサイズになっていません。これはなぜでしょうか、また、どうすればデータロードプロシージャを正しく呼び出せるのでしょうか?

A: FDecompressImage(または Image Compression Manager にある関連する関数の 1 つ)の呼び出し側は、圧縮データのすべてを単一のバッファに用意するか、または、より小さなバッファとデータロードプロシージャを用意するかを選ぶことができます。

データロード関数のバッファは最低 32K であり、codecMinimumDataSize は 32K として定義されています。

どちらのモードも考えられるので、イメージデコンプレッサコンポーネントは両方のモードをサポートする必要があります。現在のバージョンの QuickTime では、ビデオメディアハンドラはデータロードプロシージャを使うことはありませんが、基本のグラフィックスインポータは常にデータロードプロシージャを使います。

データロードプロシージャインタフェースは、イメージデコンプレッサコンポーネントによって使いやすいように設計されており、入力データを 1 回だけ受け渡す必要があるだけです。データロードプロシージャが提供される場合は、データの読み取り元となるポインタを使って定期的に呼び出し、必要と思われる最大限の先読みを指定する必要があります。必要に応じて、データロードプロシージャはポインタを更新して、事前にデータが十分に存在する状態にします。

しかし、いくつかの理由により、データロードプロシージャへの呼び出しをデコンプレッサに統合できない場合があります。たとえば、実際の伸張処理が、修正不可能なコードやハードウェアによって実行される場合です。このような場合は、データロードプロシージャを複数回呼び出し、毎回 p->bufferSize バイトを要求することにより、フレーム全体をバッファにコピーする必要があります。

基本のグラフィックスインポータは、イメージ記述の dataSize に圧縮データ全体の実際のサイズが含まれていることを常に保証します。

以下に、この仕組みを示します。

OSErr ICMDataProcPtr(Ptr *dataP, long bytesNeeded, long refcon);


  1. データロードプロシージャを呼び出すときに、データロードプロシージャのバッファへのポインタのアドレスを渡します。データロードプロシージャは、ポインタが現在もそのバッファを指しているかどうかをチェックし、ポインタの現在の値を使ってデータがどれだけ消費されたかを計算します。
Ptr dataPtr = drp->codecData;
Size bytesConsumed;
Boolean done = false;

while(! done) {
  if(dataProc) {
    err = CallICMDataProc(dataProc, &dataPtr, 10000, dataRefCon);
    if(err) goto bail;
  }
    err = consumeUpTo10000Bytes(..., dataPtr, &bytesConsumed, &done);
    if(err) goto bail;
    dataPtr += bytesConsumed;
}


  1. ポインタのアドレスの代わりに NULL を渡すと特別な意味になります。bytesNeeded パラメータがゼロの場合は、データストリームの先頭にリセットすることを要求し、bytesNeeded パラメータがゼロ以外の場合は、そのバイト数分の相対的なシークを要求します。相対的なシークの前に、データロードプロシージャは、そのバッファ中のポインタの位置を認識していることを確認する必要があります。この確認は、ゼロバイトを要求するデータプロシージャを呼び出すことにより行えます。

データストリームの先頭へのリセット:

  err = CallICMDataProc(dataProc, NULL, 0, dataRefCon);


相対的なシーク:

  err = CallICMDataProc(dataProc, &dataPtr, 0, dataRefCon);
  err = CallICMDataProc(dataProc, NULL, relativeSeekAmount, dataRefCon);


そのあとの読み取り:

  err = CallICMDataProc(dataProc, &dataPtr, bytesNeeded, dataRefCon);


  1. 割り当てたメモリブロックにデータをロードするには、BeginBand ルーチンで次の処理を実行します。
Ptr dataPtr = drp->codecData;
Ptr bufferPtr = myBuffer;
Size bytesRemaining = myBufferSize;

while(bytesRemaining > 0) {
  Size bytesToRequest;
  if(bytesRemaining < codecMinimumDataSize)
    bytesToRequest = bytesRemaining;
  else
    bytesToRequest = codecMinimumDataSize;

  err = CallICMDataProc(dataProc, &dataPtr, bytesToRequest, dataRefCon);
  if(err) goto bail;
  BlockMoveData(dataPtr, bufferPtr, bytesToRequest);
  dataPtr += bytesToRequest;
  bufferPtr += bytesToRequest;
  bytesRemaining -= bytesToRequest;
}


[2003 年 7 月 10 日]