ビットマップ ロック ビットを使用した例を使用して、C++ プロジェクトで新しい関数を作成しました。
void GetFrameData(Bitmap ^b)
{
typedef System::Drawing::Rectangle R;
R rect = R(0,0,b->Width,b->Height);
System::Drawing::Imaging::BitmapData^ bmpData = b->LockBits( rect, System::Drawing::Imaging::ImageLockMode::ReadWrite, b->PixelFormat );
// Get the address of the first line.
IntPtr ptr = bmpData->Scan0;
// Declare an array to hold the bytes of the bitmap.
// This code is specific to a bitmap with 24 bits per pixels.
int bytes = Math::Abs(bmpData->Stride) * b->Height;
array<Byte>^rgbValues = gcnew array<Byte>(bytes);
// Copy the RGB values into the array.
System::Runtime::InteropServices::Marshal::Copy( ptr, rgbValues, 0, bytes );
// Set every third value to 255.
for ( int counter = 2; counter < rgbValues->Length; counter += 3 )
rgbValues[ counter ] = 255;
// Copy the RGB values back to the bitmap
System::Runtime::InteropServices::Marshal::Copy( rgbValues, 0, ptr, bytes );
// Unlock the bits.
b->UnlockBits( bmpData );
}
この関数は CSHARP からビットマップ ファイルを取得します。どういうわけか、このロックビットを使用してビットマップからこの関数にピクセルをコピーする必要があります。
void Encoder_start(char *filename)
{
printf("Encode video file %s\n", filename);
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
// f = fopen(filename, "wb");
errn = fopen_s(&f,filename, "wb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = avcodec_alloc_frame();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
/* the image can be allocated by any means and av_image_alloc() is
* just the most convenient way if av_malloc() is to be used */
// ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
// c->pix_fmt, 32);
frame->data[0] = (uint8_t*)av_malloc(1000000);
frame->data[1] = (uint8_t*)av_malloc(1000000);
frame->data[2] = (uint8_t*)av_malloc(1000000);
frame->data[3] = (uint8_t*)av_malloc(1000000);
frame->data[4] = (uint8_t*)av_malloc(1000000);
frame->data[5] = (uint8_t*)av_malloc(1000000);
frame->data[6] = (uint8_t*)av_malloc(1000000);
frame->data[7] = (uint8_t*)av_malloc(1000000);
if (frame->data[7]==0) {
//if (ret < 0) {
fprintf(stderr, "Could not allocate raw picture buffer\n");
exit(1);
}
total_frame_counter=0;
}
void Encoder_push_frame()
{
/* encode 1 second of video */
// for(i=0;i<25;i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
fflush(stdout);
/* prepare a dummy image */
/* Y */
for(y=0;y<c->height;y++) {
for(x=0;x<c->width;x++) {
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for(y=0;y<c->height/2;y++) {
for(x=0;x<c->width/2;x++) {
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
}
}
frame->pts = total_frame_counter;
total_frame_counter++;
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
fprintf(stderr, "Error encoding frame\n");
exit(1);
}
if (got_output) {
printf("Write frame %3d (size=%5d)\n", total_frame_counter, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
}
// }
}
どのように入力するか、またテストのために av_malloc を各場所で 1000000 に設定する方法がわかりません。
そして、Encoder_push_frame関数はピクセルを取得する必要があります。または、おそらくav_mallocを使用して、push_frame関数の画像をビットマップのピクセルで埋めるという考えです。
いろいろな方法を試しましたが、まったくうまくいきませんでした。
編集
私はこのコードを使用しています:
void GetFrameData(Bitmap ^b)
{
auto bmpData = b->LockBits( System::Drawing::Rectangle(0,0,b->Width,b->Height), ImageLockMode::ReadWrite, PixelFormat::Format24bppRgb );
// The beginning of the bitmap data in memory
char* top = bmpData->Scan0.ToPointer();
// find bitmap data for the top row (if bottom-up bitmap, this is at the end)
if (bmpData->Stride < 0) {
top += Stride * (1 - b->Height);
}
for( int y = 0; y < b->Height; ++y ) {
RGBTRIPLE* row = (RGBTRIPLE*)(top + y * bmpData->Stride);
// saturate red channel
for( int x = 0; x < b->Width; ++x ) {
row[x].rgbtBlue = 255;
row[x].rgbtGreen = 255;
row[x].rgbtRed = 255;
}
// Unlock the bits.
b->UnlockBits( bmpData );
}
Rectangle では、次のように変更する必要がありました: System::Drawing::Rectangle そうでない場合、Rectangle で別の Rectangle と競合しているというエラーが発生しました。しかし、変更した後、次の行の bmpData でエラーが発生しました。
char* top = bmpData->Scan0.ToPointer();
IntelliSense: タイプ "void *" の値を使用して、タイプ "char *" のエンティティを初期化することはできません
2 番目のエラーは Stride にあります。
top += Stride * (1 - b->Height);
エラー: IntelliSense: 識別子 "Stride" は未定義です
このエラーを修正するにはどうすればよいですか。
と:
for ループを次のように変更しました。
for( int x = 0; x < b->Width; ++x ) {
row[x].rgbtBlue = 255;
row[x].rgbtGreen = 255;
row[x].rgbtRed = 255;
変更した理由は、row[x].R = 255; を実行したためです。しかし、Rは存在しない/定義されていないので、修正するにはどうすればよいですか? (私がしたことは間違っていると思います)。