I have been successfully using:
avformat_seek_file(avFormatContext_, streamIndex_, 0, frame, frame, AVSEEK_FLAG_FRAME)
This along with the example code included at the bottom has allowed me to seek to specific iframes in my videos and read frames from there until I reach the frame I want.
The problem is the video files I am using have forward and backward interpolation so the first keyframe is not at frame 0, but something like frame 8.
What I am looking for is a way to seek to the frames that exist before the first B-Frame in my video files. Any help would be appreciated.
seekFrame:
bool QVideoDecoder::seekFrame(int64_t frame)
{
if(!ok)
return false;
//printf("**** seekFrame to %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d\n",(int)frame,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk);
// Seek if:
// - we don't know where we are (Ok=false)
// - we know where we are but:
// - the desired frame is after the last decoded frame (this could be optimized: if the distance is small, calling decodeSeekFrame may be faster than seeking from the last key frame)
// - the desired frame is smaller or equal than the previous to the last decoded frame. Equal because if frame==LastLastFrameNumber we don't want the LastFrame, but the one before->we need to seek there
if( (LastFrameOk==false) || ((LastFrameOk==true) && (frame<=LastLastFrameNumber || frame>LastFrameNumber) ) )
{
//printf("\t avformat_seek_file\n");
if(ffmpeg::avformat_seek_file(pFormatCtx,videoStream,0,frame,frame,AVSEEK_FLAG_FRAME)<0)
return false;
avcodec_flush_buffers(pCodecCtx);
DesiredFrameNumber = frame;
LastFrameOk=false;
}
//printf("\t decodeSeekFrame\n");
return decodeSeekFrame(frame);
return true;
}
decodeSeekFrame:
bool QVideoDecoder::decodeSeekFrame(int after)
{
if(!ok)
return false;
//printf("decodeSeekFrame. after: %d. LLT: %d. LT: %d. LLF: %d. LF: %d. LastFrameOk: %d.\n",after,LastLastFrameTime,LastFrameTime,LastLastFrameNumber,LastFrameNumber,(int)LastFrameOk);
// If the last decoded frame satisfies the time condition we return it
//if( after!=-1 && ( LastDataInvalid==false && after>=LastLastFrameTime && after <= LastFrameTime))
if( after!=-1 && ( LastFrameOk==true && after>=LastLastFrameNumber && after <= LastFrameNumber))
{
// This is the frame we want to return
// Compute desired frame time
ffmpeg::AVRational millisecondbase = {1, 1000};
DesiredFrameTime = ffmpeg::av_rescale_q(after,pFormatCtx->streams[videoStream]->time_base,millisecondbase);
//printf("Returning already available frame %d # %d. DesiredFrameTime: %d\n",LastFrameNumber,LastFrameTime,DesiredFrameTime);
return true;
}
// The last decoded frame wasn't ok; either we need any new frame (after=-1), or a specific new frame with time>after
bool done=false;
while(!done)
{
// Read a frame
if(av_read_frame(pFormatCtx, &packet)<0)
return false; // Frame read failed (e.g. end of stream)
//printf("Packet of stream %d, size %d\n",packet.stream_index,packet.size);
if(packet.stream_index==videoStream)
{
// Is this a packet from the video stream -> decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
//printf("used %d out of %d bytes\n",len,packet.size);
//printf("Frame type: ");
//if(pFrame->pict_type == FF_B_TYPE)
// printf("B\n");
//else if (pFrame->pict_type == FF_I_TYPE)
// printf("I\n");
//else
// printf("P\n");
/*printf("codecctx time base: num: %d den: %d\n",pCodecCtx->time_base.num,pCodecCtx->time_base.den);
printf("formatctx time base: num: %d den: %d\n",pFormatCtx->streams[videoStream]->time_base.num,pFormatCtx->streams[videoStream]->time_base.den);
printf("pts: %ld\n",pts);
printf("dts: %ld\n",dts);*/
// Did we get a video frame?
if(frameFinished)
{
ffmpeg::AVRational millisecondbase = {1, 1000};
int f = packet.dts;
int t = ffmpeg::av_rescale_q(packet.dts,pFormatCtx->streams[videoStream]->time_base,millisecondbase);
if(LastFrameOk==false)
{
LastFrameOk=true;
LastLastFrameTime=LastFrameTime=t;
LastLastFrameNumber=LastFrameNumber=f;
}
else
{
// If we decoded 2 frames in a row, the last times are okay
LastLastFrameTime = LastFrameTime;
LastLastFrameNumber = LastFrameNumber;
LastFrameTime=t;
LastFrameNumber=f;
}
//printf("Frame %d # %d. LastLastT: %d. LastLastF: %d. LastFrameOk: %d\n",LastFrameNumber,LastFrameTime,LastLastFrameTime,LastLastFrameNumber,(int)LastFrameOk);
// Is this frame the desired frame?
if(after==-1 || LastFrameNumber>=after)
{
// It's the desired frame
// Convert the image format (init the context the first time)
int w = pCodecCtx->width;
int h = pCodecCtx->height;
img_convert_ctx = ffmpeg::sws_getCachedContext(img_convert_ctx,w, h, pCodecCtx->pix_fmt, w, h, ffmpeg::PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
if(img_convert_ctx == NULL)
{
printf("Cannot initialize the conversion context!\n");
return false;
}
ffmpeg::sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
// Convert the frame to QImage
LastFrame=QImage(w,h,QImage::Format_RGB888);
for(int y=0;y<h;y++)
memcpy(LastFrame.scanLine(y),pFrameRGB->data[0]+y*pFrameRGB->linesize[0],w*3);
// Set the time
DesiredFrameTime = ffmpeg::av_rescale_q(after,pFormatCtx->streams[videoStream]->time_base,millisecondbase);
LastFrameOk=true;
done = true;
} // frame of interest
} // frameFinished
} // stream_index==videoStream
av_free_packet(&packet); // Free the packet that was allocated by av_read_frame
}
//printf("Returning new frame %d # %d. LastLastT: %d. LastLastF: %d. LastFrameOk: %d\n",LastFrameNumber,LastFrameTime,LastLastFrameTime,LastLastFrameNumber,(int)LastFrameOk);
//printf("\n");
return done; // done indicates whether or not we found a frame
}
Related
first a few basic information:
OS: Win7 64Bit | GPU: GTX970
I have a staging ID3D11Texture2D wich I would like to encode.
I would like to use the texture directly via nvEncRegisterResource but it seems that i could only pass a D3D9 and no D3D11 texture. Otherwise i get a NV_ENC_ERR_UNIMPLEMENTED.
Thefore, I create an input buffer and fill it manually.
The texture is in the format DXGI_FORMAT_R8G8B8A8_UNORM. The format DXGI_FORMAT_NV12 is possibly only from Windows 8 onwards.
The input buffer format is NV_ENC_BUFFER_FORMAT_ARGB. This should also be 8 bits per color channel. Since the alpha value is interchanged I expect a wrong picture but it should still be encoded.
My process so far:
Create ID3D11Texture2D render texture
Create ID3D11Texture2D staging texture
Create NVENC input buffer with nvEncCreateInputBuffer
Create NVENC output buffer with nvEncCreateBitstreamBuffer
:: Update routine ::
Render into render texture
CopyResource() to staging texture
Fill NVENC input buffer from staging texture
Encode frame
Get data from NVENC output buffer
As you can see, I encode only one frame per update.
So far everything works without error, but if i look at the frame the picture size is wrong.
That should be 1280 x 720. If I also try to pass more than one frame then I get a broken file.
I understand that in H.264 my first frame is an I-frame and the following should be a P-frame.
Now my code:
:: Create input buffer
NVENCSTATUS RenderManager::CreateInputBuffer()
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_CREATE_INPUT_BUFFER createInputBufferParams = {};
createInputBufferParams.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
createInputBufferParams.width = m_width;
createInputBufferParams.height = m_height;
createInputBufferParams.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
createInputBufferParams.bufferFmt = NV_ENC_BUFFER_FORMAT_ARGB;
nvStatus = m_pEncodeAPI->nvEncCreateInputBuffer(m_pEncoder, &createInputBufferParams);
if (nvStatus != NV_ENC_SUCCESS) return nvStatus;
m_pEncoderInputBuffer = createInputBufferParams.inputBuffer;
return nvStatus;
}
:: Create output buffer
NVENCSTATUS RenderManager::CreateOutputBuffer()
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
NV_ENC_CREATE_BITSTREAM_BUFFER createBitstreamBufferParams = {};
createBitstreamBufferParams.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
createBitstreamBufferParams.size = 2 * 1024 * 1024;
createBitstreamBufferParams.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
nvStatus = m_pEncodeAPI->nvEncCreateBitstreamBuffer(m_pEncoder, &createBitstreamBufferParams);
if (nvStatus != NV_ENC_SUCCESS) return nvStatus;
m_pEncoderOutputBuffer = createBitstreamBufferParams.bitstreamBuffer;
return nvStatus;
}
:: Fill input buffer
NVENCSTATUS RenderManager::WriteInputBuffer(ID3D11Texture2D* pTexture)
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
HRESULT result = S_OK;
// get data from staging texture
D3D11_MAPPED_SUBRESOURCE mappedResource;
result = m_pContext->Map(pTexture, 0, D3D11_MAP_READ, 0, &mappedResource);
if (FAILED(result)) return NV_ENC_ERR_GENERIC;
m_pContext->Unmap(pTexture, 0);
// lock input buffer
NV_ENC_LOCK_INPUT_BUFFER lockInputBufferParams = {};
lockInputBufferParams.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
lockInputBufferParams.inputBuffer = m_pEncoderInputBuffer;
nvStatus = m_pEncodeAPI->nvEncLockInputBuffer(m_pEncoder, &lockInputBufferParams);
if (nvStatus != NV_ENC_SUCCESS) return nvStatus;
unsigned int pitch = lockInputBufferParams.pitch;
//ToDo: Convert R8G8B8A8 to A8R8G8B8
// write into buffer
memcpy(lockInputBufferParams.bufferDataPtr, mappedResource.pData, m_height * mappedResource.RowPitch);
// unlock input buffer
nvStatus = m_pEncodeAPI->nvEncUnlockInputBuffer(m_pEncoder, m_pEncoderInputBuffer);
return nvStatus;
}
:: Encode frame
NVENCSTATUS RenderManager::EncodeFrame()
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
int8_t* qpDeltaMapArray = NULL;
unsigned int qpDeltaMapArraySize = 0;
NV_ENC_PIC_PARAMS encPicParams = {};
encPicParams.version = NV_ENC_PIC_PARAMS_VER;
encPicParams.inputWidth = m_width;
encPicParams.inputHeight = m_height;
encPicParams.inputBuffer = m_pEncoderInputBuffer;
encPicParams.outputBitstream = m_pEncoderOutputBuffer;
encPicParams.bufferFmt = NV_ENC_BUFFER_FORMAT_ARGB;
encPicParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
encPicParams.qpDeltaMap = qpDeltaMapArray;
encPicParams.qpDeltaMapSize = qpDeltaMapArraySize;
nvStatus = m_pEncodeAPI->nvEncEncodePicture(m_pEncoder, &encPicParams);
return nvStatus;
}
:: Read from output buffer
NVENCSTATUS RenderManager::ReadOutputBuffer()
{
NVENCSTATUS nvStatus = NV_ENC_SUCCESS;
// lock output buffer
NV_ENC_LOCK_BITSTREAM lockBitstreamBufferParams = {};
lockBitstreamBufferParams.version = NV_ENC_LOCK_BITSTREAM_VER;
lockBitstreamBufferParams.doNotWait = 0;
lockBitstreamBufferParams.outputBitstream = m_pEncoderOutputBuffer;
nvStatus = m_pEncodeAPI->nvEncLockBitstream(m_pEncoder, &lockBitstreamBufferParams);
if (nvStatus != NV_ENC_SUCCESS) return nvStatus;
void* pData = lockBitstreamBufferParams.bitstreamBufferPtr;
unsigned int size = lockBitstreamBufferParams.bitstreamSizeInBytes;
// read from buffer
PlatformManager::SaveToFile("TEST", static_cast<char*>(pData), size);
// unlock output buffer
nvStatus = m_pEncodeAPI->nvEncUnlockBitstream(m_pEncoder, m_pEncoderOutputBuffer);
return nvStatus;
}
m_width and m_height are always 1280 and 720.
Why is the image size wrong and how i have to fill the input buffer with more than one frame ?
Many thanks for your help,
Alexander
I've been trying to copy a AVFrame just like what was answered in ffmpeg: make a copy from a decoded frame (AVFrame). However but I can't seem to get it to get a positive return code from av_frame_copy().
Here is basically what I'm doing:
AVFrame *copyFrame = NULL;
copyFrame = av_frame_alloc();
int return_code = av_frame_copy(copyFrame, originalFrame);
if(return_code < 0){
fprintf(stderr, "av_frame_copy failed with return code %d\n", return_code);
return(1);
}
If it helps, the return code I get from av_frame_copy is -22.
If you read the documentation for av_frame_copy, it says "This function does not allocate anything, dst must be already initialized and allocated with the same parameters as src."
av_frame_alloc doesn't do anything other than allocate the AVFrame struct and initialize it to some default values. Most importantly, it doesn't allocate buffers for the frame data or prepare the frame to be used. av_frame_copy is failing because the destination frame doesn't have the correct pixel format set or buffers allocated.
If you want to clone a frame (by incrementing its reference counter, not creating a deep copy) you can use av_frame_clone or av_frame_ref.
If you want to move the frame you can use av_frame_move_ref.
But you probably want to do a proper deep copy. In that case, you can look at the source code of the av_frame_make_writable. This function makes a deep copy of the frame if it isn't writeable, so we can use the same logic to make a deep copy of the frame here:
AVFrame *copyFrame = av_frame_alloc();
copyFrame->format = frame->format;
copyFrame->width = frame->width;
copyFrame->height = frame->height;
copyFrame->channels = frame->channels;
copyFrame->channel_layout = frame->channel_layout;
copyFrame->nb_samples = frame->nb_samples;
av_frame_get_buffer(copyFrame, 32);
av_frame_copy(copyFrame, frame);
av_frame_copy_props(copyFrame, frame);
Note that I haven't checked for errors in the functions I've called. You should do that in your real code. I omitted it here for brevity.
I had AVFrame * on GPU. This worked for me:
int ret;
AVFrame *dst;
dst = av_frame_alloc();
memcpy(dst,src,sizeof(AVFrame));
dst->format = src->format;
dst->width = src->width;
dst->height = src->height;
dst->channels = src->channels;
dst->channel_layout = src->channel_layout;
dst->nb_samples = src->nb_samples;
dst->extended_data = src->extended_data;
memcpy(dst->data, src->data, sizeof(src->data));
ret = av_frame_copy_props(dst, src);
if (ret < 0) { av_frame_unref(dst);}
AVFrame *copyFrame = new AVFrame;
copyFrame = av_frame_alloc();
*copyFrame = *inAVFrame;
if (int iRet = av_frame_copy(copyFrame, inAVFrame) == 0) {
//av_log(NULL, AV_LOG_INFO, "Ok");
} else {
//av_log(NULL, AV_LOG_INFO, "Error: %s\n", AV_err2str(iRet));
}
I'm currently using these settings with OpenAL and recording from a Mic:
BUFFERSIZE 4410
FREQ 22050 // Sample rate
CAP_SIZE 10000 // How much to capture at a time (affects latency)
AL_FORMAT_MONO16
Is it possible to go lower in recording quality? I've tried reducing the sample rate but the end result is a faster playback speed.
Alright, so this is some of the most hacky code I've ever written, and I truly hope no one in their right mind ever uses it in production... just sooooo many bad things.
But to answer your question, I've been able to get the quality down to 8bitMono recording at 11025. However, everything I've recorded from my mic comes with significant amounts of static, and I'm not entirely sure I know why. I've generated 8bit karplus-strong string plucks that sound fantastic, so it could just be my recording device.
#include <AL/al.h>
#include <AL/alc.h>
#include <conio.h>
#include <stdio.h>
#include <vector>
#include <time.h>
void sleep( clock_t wait )
{
clock_t goal;
goal = wait + clock();
while( goal > clock() )
;
}
#define BUFFERSIZE 4410
const int SRATE = 11025;
int main()
{
std::vector<ALchar> vBuffer;
ALCdevice *pDevice = NULL;
ALCcontext *pContext = NULL;
ALCdevice *pCaptureDevice;
const ALCchar *szDefaultCaptureDevice;
ALint iSamplesAvailable;
ALchar Buffer[BUFFERSIZE];
ALint iDataSize = 0;
ALint iSize;
// NOTE : This code does NOT setup the Wave Device's Audio Mixer to select a recording input
// or a recording level.
pDevice = alcOpenDevice(NULL);
pContext = alcCreateContext(pDevice, NULL);
alcMakeContextCurrent(pContext);
printf("Capture Application\n");
if (pDevice == NULL)
{
printf("Failed to initialize OpenAL\n");
//Shutdown code goes here
return 0;
}
// Check for Capture Extension support
pContext = alcGetCurrentContext();
pDevice = alcGetContextsDevice(pContext);
if (alcIsExtensionPresent(pDevice, "ALC_EXT_CAPTURE") == AL_FALSE){
printf("Failed to detect Capture Extension\n");
//Shutdown code goes here
return 0;
}
// Get list of available Capture Devices
const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
if (pDeviceList){
printf("\nAvailable Capture Devices are:-\n");
while (*pDeviceList)
{
printf("%s\n", pDeviceList);
pDeviceList += strlen(pDeviceList) + 1;
}
}
// Get the name of the 'default' capture device
szDefaultCaptureDevice = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
printf("\nDefault Capture Device is '%s'\n\n", szDefaultCaptureDevice);
pCaptureDevice = alcCaptureOpenDevice(szDefaultCaptureDevice, SRATE, AL_FORMAT_MONO8, BUFFERSIZE);
if (pCaptureDevice)
{
printf("Opened '%s' Capture Device\n\n", alcGetString(pCaptureDevice, ALC_CAPTURE_DEVICE_SPECIFIER));
// Start audio capture
alcCaptureStart(pCaptureDevice);
// Wait for any key to get pressed before exiting
while (!_kbhit())
{
// Release some CPU time ...
sleep(1);
// Find out how many samples have been captured
alcGetIntegerv(pCaptureDevice, ALC_CAPTURE_SAMPLES, 1, &iSamplesAvailable);
printf("Samples available : %d\r", iSamplesAvailable);
// When we have enough data to fill our BUFFERSIZE byte buffer, grab the samples
if (iSamplesAvailable > (BUFFERSIZE / 2))
{
// Consume Samples
alcCaptureSamples(pCaptureDevice, Buffer, BUFFERSIZE / 2);
// Write the audio data to a file
//fwrite(Buffer, BUFFERSIZE, 1, pFile);
for(int i = 0; i < BUFFERSIZE / 2; i++){
vBuffer.push_back(Buffer[i]);
}
// Record total amount of data recorded
iDataSize += BUFFERSIZE / 2;
}
}
// Stop capture
alcCaptureStop(pCaptureDevice);
// Check if any Samples haven't been consumed yet
alcGetIntegerv(pCaptureDevice, ALC_CAPTURE_SAMPLES, 1, &iSamplesAvailable);
while (iSamplesAvailable)
{
if (iSamplesAvailable > (BUFFERSIZE / 2))
{
alcCaptureSamples(pCaptureDevice, Buffer, BUFFERSIZE / 2);
for(int i = 0; i < BUFFERSIZE/2; i++){
vBuffer.push_back(Buffer[i]);
}
iSamplesAvailable -= (BUFFERSIZE / 2);
iDataSize += BUFFERSIZE;
}
else
{
//TODO::Fix
alcCaptureSamples(pCaptureDevice, Buffer, iSamplesAvailable);
for(int i = 0; i < BUFFERSIZE/2; i++){
vBuffer.push_back(Buffer[i]);
}
iDataSize += iSamplesAvailable * 2;
iSamplesAvailable = 0;
}
}
alcCaptureCloseDevice(pCaptureDevice);
}
//TODO::Make less hacky
ALuint bufferID; // The OpenAL sound buffer ID
ALuint sourceID; // The OpenAL sound source
// Create sound buffer and source
alGenBuffers(1, &bufferID);
alGenSources(1, &sourceID);
alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);
alBufferData(bufferID, AL_FORMAT_MONO8, &vBuffer[0], static_cast<ALsizei>(vBuffer.size()), SRATE);
// Attach sound buffer to source
alSourcei(sourceID, AL_BUFFER, bufferID);
// Finally, play the sound!!!
alSourcePlay(sourceID);
printf("Press any key to continue...");
getchar();
return 0;
}
As you can see from:
alBufferData(bufferID, AL_FORMAT_MONO8, &vBuffer[0], static_cast<ALsizei>(vBuffer.size()), SRATE);
I've verified that this is the case. For demonstration code I'm okay throwing this example out there, but I wouldn't ever use it in production.
I'm not sure but for me FREQ is the output frequency but not the sample rate.
define sampling-rate 48000
see this link : http://supertux.lethargik.org/wiki/OpenAL_Configuration
I work on a video player yuv420p with ffmpeg but it's not working and i can't find out why. I spend the whole week on it...
So i have a test which just decode some frame and read it, but the output always differ, and it's really weird.
I use a video (mp4 yuv420p) which color one black pixel in more each frame :
For the video, put http://sendvid.com/b1sgf8r1 on a website like http://www.telechargerunevideo.com/en/
VideoContext is just a little struct:
struct VideoContext {
unsigned int currentFrame;
std::size_t size;
int width;
int height;
bool pause;
AVFormatContext* formatCtx;
AVCodecContext* codecCtxOrig;
AVCodecContext* codecCtx;
int streamIndex;
};
So i have a function to count the number of black pixels:
std::size_t checkFrameNb(const AVFrame* frame) {
std::size_t nb = 0;
for (int y = 0; y < frame->height; ++y) {
for (int x = 0 ; x < frame->width; ++x) {
if (frame->data[0][(y * frame->linesize[0]) + x] == BLACK_FRAME.y
&& frame->data[1][(y / 2 * frame->linesize[1]) + x / 2] == BLACK_FRAME.u
&& frame->data[2][(y / 2 * frame->linesize[2]) + x / 2] == BLACK_FRAME.v)
++nb;
}
}
return nb;
}
And this is how i decode one frame:
const AVFrame* VideoDecoder::nextFrame(entities::VideoContext& context) {
int frameFinished;
AVPacket packet;
// Allocate video frame
AVFrame* frame = av_frame_alloc();
if(frame == nullptr)
throw;
// Initialize frame->linesize
avpicture_fill((AVPicture*)frame, nullptr, AV_PIX_FMT_YUV420P, context.width, context.height);
while(av_read_frame(context.formatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if(packet.stream_index == context.streamIndex) {
// Decode video frame
avcodec_decode_video2(context.codecCtx, frame, &frameFinished, &packet);
// Did we get a video frame?
if(frameFinished) {
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
++context.currentFrame;
return frame;
}
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
throw core::GlobalException("nextFrame", "Frame decode failed");
}
There is already something wrong?
Maybe the context initialization will be useful:
entities::VideoContext VideoLoader::loadVideoContext(const char* file,
const int width,
const int height) {
entities::VideoContext context;
// Register all formats and codecs
av_register_all();
context.formatCtx = avformat_alloc_context();
// Open video file
if(avformat_open_input(&context.formatCtx, file, nullptr, 0) != 0)
throw; // Couldn't open file
// Retrieve stream information
if(avformat_find_stream_info(context.formatCtx, nullptr) > 0)
throw; // Couldn't find stream information
// Dump information about file onto standard error
//av_dump_format(m_formatCtx, 0, file, 1);
// Find the first video stream because we don't need more
for(unsigned int i = 0; i < context.formatCtx->nb_streams; ++i)
if(context.formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
context.streamIndex = i;
context.codecCtx = context.formatCtx->streams[i]->codec;
break;
}
if(context.codecCtx == nullptr)
throw; // Didn't find a video stream
// Find the decoder for the video stream
AVCodec* codec = avcodec_find_decoder(context.codecCtx->codec_id);
if(codec == nullptr)
throw; // Codec not found
// Copy context
if ((context.codecCtxOrig = avcodec_alloc_context3(codec)) == nullptr)
throw;
if(avcodec_copy_context(context.codecCtxOrig, context.codecCtx) != 0)
throw; // Error copying codec context
// Open codec
if(avcodec_open2(context.codecCtx, codec, nullptr) < 0)
throw; // Could not open codec
context.currentFrame = 0;
decoder::VideoDecoder::setVideoSize(context);
context.pause = false;
context.width = width;
context.height = height;
return std::move(context);
}
I know it's not a little piece of code, if you have any idea too make an exemple more brief, go on.
And if someone have an idea about this issue, there is my output:
9 - 10 - 12 - 4 - 10 - 14 - 11 - 8 - 9 - 10
But i want :
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10
PS:
get fps and video size are copy paste code of opencv
We are developing software for slide show creation and use OpenGL.
We use FBO + PBO for fast data reading from VGA to RAM but on some video cards from ATI we faced with the following problems:
swapping RGB components
pixel shifting
There are no problems if we do not use PBO.
Also we have noticed that the aspect ratio of PBO/FBO (4:3) solve the pixel shifting problem.
Any thoughts or suggestions?
Here are more details:
ATI Radeon HD 3650
PBO code:
public bool PBO_Initialize(
int bgl_size_w,
int bgl_size_h)
{
PBO_Release();
if (mCSGL12Control1 != null)
{
GL mGL = mCSGL12Control1.GetGL();
mCSGL12Control1.wgl_MakeCurrent();
//
// check PBO is supported by your video card
if (mGL.bglGenBuffersARB == true &&
mGL.bglBindBufferARB == true &&
mGL.bglBufferDataARB == true &&
mGL.bglBufferSubDataARB == true &&
mGL.bglMapBufferARB == true &&
mGL.bglUnmapBufferARB == true &&
mGL.bglDeleteBuffersARB == true &&
mGL.bglGetBufferParameterivARB == true)
{
mGL.glGenBuffersARB(2, _pbo_imageBuffers);
int clientHeight1 = bgl_size_h / 2;
int clientHeight2 = bgl_size_h - clientHeight1;
int clientSize1 = bgl_size_w * clientHeight1 * 4;
int clientSize2 = bgl_size_w * clientHeight2 * 4;
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
mGL.glBufferDataARB(GL.GL_PIXEL_PACK_BUFFER_ARB, clientSize1, IntPtr.Zero,
GL.GL_STREAM_READ_ARB);
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
mGL.glBufferDataARB(GL.GL_PIXEL_PACK_BUFFER_ARB, clientSize2, IntPtr.Zero,
GL.GL_STREAM_READ_ARB);
return true;
}
}
return false;
}
...
PBO read data back to memory
int clientHeight1 = _bgl_size_h / 2;
int clientHeight2 = _bgl_size_h - clientHeight1;
int clientSize1 = _bgl_size_w * clientHeight1 * 4;
int clientSize2 = _bgl_size_w * clientHeight2 * 4;
//mGL.glPushAttrib(GL.GL_VIEWPORT_BIT | GL.GL_COLOR_BUFFER_BIT);
// Bind two different buffer objects and start the glReadPixels
// asynchronously. Each call will return directly after
// starting the DMA transfer.
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
mGL.glReadPixels(0, 0, _bgl_size_w, clientHeight1, imageFormat,
pixelTransferMethod, IntPtr.Zero);
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
mGL.glReadPixels(0, clientHeight1, _bgl_size_w, clientHeight2, imageFormat,
pixelTransferMethod, IntPtr.Zero);
//mGL.glPopAttrib();
mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
// Process partial images. Mapping the buffer waits for
// outstanding DMA transfers into the buffer to finish.
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
IntPtr pboMemory1 = mGL.glMapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB,
GL.GL_READ_ONLY_ARB);
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
IntPtr pboMemory2 = mGL.glMapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB,
GL.GL_READ_ONLY_ARB);
System.Runtime.InteropServices.Marshal.Copy(pboMemory1, _bgl_rgbaData_out, 0, clientSize1);
System.Runtime.InteropServices.Marshal.Copy(pboMemory2, _bgl_rgbaData_out, clientSize1, clientSize2);
// Unmap the image buffers
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[0]);
mGL.glUnmapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB);
mGL.glBindBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB, _pbo_imageBuffers[1]);
mGL.glUnmapBufferARB(GL.GL_PIXEL_PACK_BUFFER_ARB);
FBO initialization
private static void FBO_Initialize(GL mGL,
ref int[] bgl_texture,
ref int[] bgl_framebuffer,
ref int[] bgl_renderbuffer,
ref byte[] bgl_rgbaData,
int bgl_size_w,
int bgl_size_h)
{
// Texture
mGL.glGenTextures(1, bgl_texture);
mGL.glBindTexture(GL.GL_TEXTURE_2D, bgl_texture[0]);
mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
mGL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
IntPtr null_ptr = new IntPtr(0);
// <null> means reserve texture memory, but texels are undefined
mGL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, bgl_size_w, bgl_size_h, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null_ptr);
//
mGL.glGenFramebuffersEXT(1, bgl_framebuffer);
mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, bgl_framebuffer[0]);
mGL.glGenRenderbuffersEXT(1, bgl_renderbuffer);
mGL.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, bgl_renderbuffer[0]);
mGL.glRenderbufferStorageEXT(GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT24, bgl_size_w, bgl_size_h);
mGL.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT,
GL.GL_TEXTURE_2D, bgl_texture[0], 0);
mGL.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT,
GL.GL_RENDERBUFFER_EXT, bgl_renderbuffer[0]);
// Errors?
int status = mGL.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT);
if (status != GL.GL_FRAMEBUFFER_COMPLETE_EXT || mGL.glGetError() != GL.GL_NO_ERROR)
{
mGL.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT,
GL.GL_TEXTURE_2D, 0, 0);
mGL.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT,
GL.GL_RENDERBUFFER_EXT, 0);
mGL.glBindTexture(GL.GL_TEXTURE_2D, 0);
mGL.glDeleteTextures(1, bgl_texture);
mGL.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, 0);
mGL.glDeleteRenderbuffersEXT(1, bgl_renderbuffer);
mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
mGL.glDeleteFramebuffersEXT(1, bgl_framebuffer);
throw new Exception("Bad framebuffer.");
}
mGL.glDrawBuffer(GL.GL_COLOR_ATTACHMENT0_EXT);
mGL.glReadBuffer(GL.GL_COLOR_ATTACHMENT0_EXT); // For glReadPixels()
mGL.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
mGL.glDrawBuffer(GL.GL_BACK);
mGL.glReadBuffer(GL.GL_BACK);
mGL.glBindTexture(GL.GL_TEXTURE_2D, 0);
bgl_rgbaData = new byte[bgl_size_w * bgl_size_h * 4];
}
It seems that re-installing/updating VGA Driver does solve this problem.
Really strange behaviour (also, it may be that the official notebook driver is old/buggy/etc. and causes the problem, so updating with the latest driver from AMD, for this vga-chip series, seems affect/solve the problem. Also I'm not sure if the previouse driver was set up correct thus I say re-installing/updating)
Thank you all for help.