I use the following code to encode an incoming h264 stream:
int ret;
ffmpeg::AVDictionary *opts2 = NULL;
av_dict_set(&opts2, "preset", "medium", 0);
av_dict_set(&opts2, "crf", "29", 0);
av_dict_set(&opts2, "profile", "baseline", 0);
av_dict_set(&opts2, "level", "30", 0);
av_dict_set(&opts2, "maxrate", "200000", 0);
av_dict_set(&opts2, "minrate", "0", 0);
av_dict_set(&opts2, "bufsize", "2000000", 0);
ffmpeg::AVOutputFormat* fmt = ffmpeg::av_guess_format("mpeg", NULL, NULL);
// Open the context
//---------------------------------------------------------------------
outFormatCtx = ffmpeg::avformat_alloc_context();
if (!outFormatCtx)
{
return false;
}
//Set the output format
//----------------------------------------------------------------------
outFormatCtx->oformat = fmt;
// Open the output file
//-------------------------------------
if (!(outFormatCtx->flags & AVFMT_NOFILE))
{
ret = ffmpeg::avio_open2(&outFormatCtx->pb, "Record.avi", AVIO_FLAG_WRITE, NULL, NULL);
if (ret < 0)
{
return false;
}
}
// Create the output stream
// -------------------------------------
ffmpeg::AVStream* out_stream = ffmpeg::avformat_new_stream(outFormatCtx, inputStream->codec->codec);
if (!out_stream)
{
return false;
}
//Set the stream parameters
//-------------------------------------
ret = ffmpeg::avcodec_copy_context(out_stream->codec, inputStream->codec);
if (ret < 0)
{
return false;
}
// Check then setup for global headers
//-------------------------------------
if (outFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
av_dump_format(outFormatCtx, 0, "Record.avi", 1);
//Write the header
//--------------------------------------
ret = ffmpeg::avformat_write_header(outFormatCtx, &opts2);
if (ret < 0)
{
return false;
}
However I always get the warning:
"VBV buffer size not set, using default size of 130KB\n"
"If you want the mpeg file to be compliant to some specification\n"
"Like DVD, VCD or others, make sure you set the correct buffer size\n"
I have tried very hard, but how could I set this VBV buffer size?
Related
I'm trying to encode a series of Cairo surfaces by using libav. Here I initialize AV stuff:
AVStream* video_stream;
AVCodec* vcodec;
gint ret;
/* Setup video container */
avformat_alloc_output_context2(&img->video_format_context, NULL, NULL, filename);
if (img->video_format_context == NULL)
{
img_message(img, TRUE, _("Failed to find a suitable container for %s\n"),filename);
return FALSE;
}
ret = avio_open(&img->video_format_context->pb, filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
img_message(img, TRUE, _("Couldn't write output file %s\n"),filename);
return FALSE;
}
/* Setup video codec */
vcodec = avcodec_find_encoder(codec_id);
if (!vcodec)
{
img_message(img, TRUE, _("Couldn't find any encoder for %s\n"),filename);
return FALSE;
}
/* Create video stream */
video_stream = avformat_new_stream(img->video_format_context, vcodec);
video_stream->id = 0;
if (! video_stream)
{
img_message(img, TRUE, _("Couldn't not allocate video stream\n"));
return FALSE;
}
/* Allocate video encoding context */
img->codec_context = avcodec_alloc_context3(vcodec);
if (! img->codec_context)
{
img_message(img, TRUE, _("Couldn't allocate video enconding context\n"));
return FALSE;
}
/* Setup video enconding context parameters */
img->codec_context->codec_id = codec_id;
img->codec_context->codec_type = AVMEDIA_TYPE_VIDEO;
img->codec_context->width = img->video_size[0];
img->codec_context->height = img->video_size[1];
img->codec_context->sample_aspect_ratio = (struct AVRational) {1, 1};
img->codec_context->pix_fmt = vcodec->pix_fmts[0];
img->codec_context->framerate = av_d2q(frame_rate, INT_MAX);
if (codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9 || codec_id == AV_CODEC_ID_THEORA || codec_id == AV_CODEC_ID_FLV1 ||
AV_CODEC_ID_MPEG1VIDEO || codec_id == AV_CODEC_ID_MPEG2VIDEO)
img->codec_context->bit_rate = round(bitrate_crf * 1000000);
img->codec_context->time_base = av_inv_q(img->codec_context->framerate);
video_stream->time_base = img->codec_context->time_base;
if (img->video_format_context->oformat->flags & AVFMT_GLOBALHEADER)
img->codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
/* Some codecs require the CRF value */
if (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_H265)
{
gchar *crf = g_strdup_printf("%i", bitrate_crf);
av_opt_set(img->codec_context->priv_data, "crf", crf, AV_OPT_SEARCH_CHILDREN);
g_free(crf);
}
/* Set exporting stage to be multithreaded */
AVDictionary* opts = NULL;
av_dict_set(&opts, "threads", "auto", 0);
/* Open video encoder */
ret = avcodec_open2(img->codec_context, vcodec, &opts);
if (ret < 0)
{
img_message(img, TRUE, _("Failed to open the video encoder\n"));
return FALSE;
}
/* Copy video encoder parameters to output stream */
ret = avcodec_parameters_from_context(video_stream->codecpar, img->codec_context);
if (ret < 0)
{
img_message(img, TRUE, _("Failed to copy video encoder parameters to output stream\n"));
return FALSE;
}
/* AVFRAME stuff */
img->video_frame = av_frame_alloc();
img->video_frame->format = AV_PIX_FMT_RGBA;
img->video_frame->width = img->video_size[0];
img->video_frame->height = img->video_size[1];
av_frame_make_writable(img->video_frame);
ret = av_frame_get_buffer(img->video_frame, 1);
if (ret < 0)
img_message(img,TRUE, _("Could not allocate the video frame data\n"));
img->video_packet = av_packet_alloc();
And here I called repeatedly (the function is called somewehere else) av_send_frame() but it throws the error in the subject:
gint width, height, stride, row, col, offset;
uint8_t *pix;
/* Image info and pixel data */
width = cairo_image_surface_get_width( surface );
height = cairo_image_surface_get_height( surface );
stride = cairo_image_surface_get_stride( surface );
pix = cairo_image_surface_get_data( surface );
for( row = 0; row < height; row++ )
{
for( col = 0; col < width; col++ )
{
offset = 3 * col + row * img->video_frame->linesize[0];
img->video_frame->data[0][offset + 0] = pix[0];
img->video_frame->data[0][offset + 1] = pix[1];
img->video_frame->data[0][offset + 2] = pix[2];
}
}
img_export_encode_av_frame(img->video_frame, img->video_format_context, img->codec_context, img->video_packet);
return TRUE;
}
void img_export_encode_av_frame(AVFrame *frame, AVFormatContext *fmt, AVCodecContext *ctx, AVPacket *pkt)
{
gint ret;
/* send the frame to the encoder */
ret = avcodec_send_frame(ctx, frame);
if (ret < 0)
g_print("Error sending a frame for encoding\n");
while (ret >= 0)
{
ret = avcodec_receive_packet(ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0)
g_print("Error during encoding\n");
av_interleaved_write_frame(fmt, pkt);
av_packet_unref(pkt);
}
}
I googled here also but with no luck. It seems I'm the only one to encode a cairo surface. Grepping the error message in ffmpeg sources didn't help. How do I set the stride? I read ffmpeg does it for me once I allocate the buffer for the frame but in my case it seems it doesn't. Where am I wrong?
I have built a class that reads avi file and displays it.
This is the defination for the class.
typedef struct {
AVFormatContext *fmt_ctx;
int stream_idx;
AVStream *video_stream;
AVCodecContext *codec_ctx;
AVCodec *decoder;
AVPacket *packet;
AVFrame *av_frame;
AVFrame *gl_frame;
struct SwsContext *conv_ctx;
unsigned int frame_tex;
}AppData;
class ClipPlayer{
private:
AppData data;
std::vector< AVFrame* > cache;
public:
ClipPlayer();
ClipPlayer(const ClipPlayer& player);
ClipPlayer& operator=(const ClipPlayer& player);
~ClipPlayer();
void initializeAppData();
void clearAppData();
bool readFrame();
bool initReadFrame();
void playCache();
void init();
void draw();
void reset();
}
In the init function the AVI file is read and the frames are saved in memory.
void init()
{
initializeAppData();
// open video
if (avformat_open_input(&data.fmt_ctx, stdstrPathOfVideo.c_str(), NULL, NULL) < 0) {
clearAppData();
return;
}
// find stream info
if (avformat_find_stream_info(data.fmt_ctx, NULL) < 0) {
clearAppData();
return;
}
// find the video stream
for (unsigned int i = 0; i < data.fmt_ctx->nb_streams; ++i)
{
if (data.fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
data.stream_idx = i;
break;
}
}
if (data.stream_idx == -1)
{
clearAppData();
return;
}
data.video_stream = data.fmt_ctx->streams[data.stream_idx];
data.codec_ctx = data.video_stream->codec;
// find the decoder
data.decoder = avcodec_find_decoder(data.codec_ctx->codec_id);
if (data.decoder == NULL)
{
clearAppData();
return;
}
// open the decoder
if (avcodec_open2(data.codec_ctx, data.decoder, NULL) < 0)
{
clearAppData();
return;
}
// allocate the video frames
data.av_frame = av_frame_alloc();
data.gl_frame = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_RGBA, data.codec_ctx->width,
data.codec_ctx->height);
uint8_t *internal_buffer = (uint8_t *)av_malloc(size * sizeof(uint8_t));
avpicture_fill((AVPicture *)data.gl_frame, internal_buffer, AV_PIX_FMT_RGBA,
data.codec_ctx->width, data.codec_ctx->height);
data.packet = (AVPacket *)av_malloc(sizeof(AVPacket));
}
/////////////////////////////////////////////////////////////
bool ClipPlayer::initReadFrame()
{
do {
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
int error = av_read_frame(data.fmt_ctx, data.packet);
if (error)
{
av_free_packet(data.packet);
return false;
}
if (data.packet->stream_index == data.stream_idx)
{
int frame_finished = 0;
if (avcodec_decode_video2(data.codec_ctx, data.av_frame, &frame_finished,
data.packet) < 0) {
av_free_packet(data.packet);
return false;
}
if (frame_finished)
{
if (!data.conv_ctx)
{
data.conv_ctx = sws_getContext(data.codec_ctx->width,
data.codec_ctx->height, data.codec_ctx->pix_fmt,
data.codec_ctx->width, data.codec_ctx->height, AV_PIX_FMT_RGBA,
SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(data.conv_ctx, data.av_frame->data, data.av_frame->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
data.gl_frame->data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
AVFrame *cachedValue = av_frame_alloc();
cachedValue->format = data.av_frame->format;
cachedValue->width = data.av_frame->width;
cachedValue->height = data.av_frame->height;
cachedValue->channels = data.av_frame->channels;
cachedValue->channel_layout = data.av_frame->channel_layout;
cachedValue->nb_samples = data.av_frame->nb_samples;
av_frame_get_buffer(cachedValue, 32);
av_frame_copy(cachedValue, data.av_frame);
av_frame_copy_props(cachedValue, data.av_frame);
cache.push_back((cachedValue));
}
}
} while (data.packet->stream_index != data.stream_idx);
////////////////////////////////////////////////////////////////////
In the play cache function the frames are displayed
void ClipPlayer::playCache()
{
glActiveTexture(GL_TEXTURE0);
sws_scale(data.conv_ctx, cache[loop]->data, cache[loop]->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,data.gl_frame->data[0]);
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
}
In the destructor i try to free the memory
~ClipPlayer()
{
for (auto &frame : cache)
{
av_freep(frame);
}
}
I am not very proficient in using FFmpeg , my question is that have i freed the memory properly.
Your code two apparent problem.
You should use av_frame_unref() instead of av_freep() for AVFrames.
avpicture_fill is deprecated long ago. IF your ffmpeg installation is old. Update it. Otherwise use av_image_fill_arrays() instead.
You can refer up to date API documentation here: http://www.ffmpeg.org/doxygen/trunk/index.html
Hope that helps.
I am reading a AVI file using ffMpeg.
I want to cache the file into a vector and resuse it later.
This is my code.
typedef struct {
AVFormatContext *fmt_ctx;
int stream_idx;
AVStream *video_stream;
AVCodecContext *codec_ctx;
AVCodec *decoder;
AVPacket *packet;
AVFrame *av_frame;
AVFrame *gl_frame;
struct SwsContext *conv_ctx;
unsigned int frame_tex;
}AppData;
AppData data;
Here i am caching the file to a std::vector
std::vector< AVFrame* > cache;
bool initReadFrame()
{
do {
glBindTexture(GL_TEXTURE_2D, data.frame_tex);
int error = av_read_frame(data.fmt_ctx, data.packet);
if (error)
{
av_free_packet(data.packet);
return false;
}
if (data.packet->stream_index == data.stream_idx)
{
int frame_finished = 0;
if (avcodec_decode_video2(data.codec_ctx, data.av_frame, &frame_finished,
data.packet) < 0) {
av_free_packet(data.packet);
return false;
}
if (frame_finished)
{
if (!data.conv_ctx)
{
data.conv_ctx = sws_getContext(data.codec_ctx->width,
data.codec_ctx->height, data.codec_ctx->pix_fmt,
data.codec_ctx->width, data.codec_ctx->height, AV_PIX_FMT_RGBA,
SWS_BICUBIC, NULL, NULL, NULL);
}
sws_scale(data.conv_ctx, data.av_frame->data, data.av_frame->linesize, 0,
data.codec_ctx->height, data.gl_frame->data, data.gl_frame->linesize);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
data.gl_frame->data[0]);
cache.push_back(av_frame_clone(data.gl_frame)); // Pushing AVFrame* to vector
}
}
av_free_packet(data.packet);
} while (data.packet->stream_index != data.stream_idx);
return true;
}
here i am trying to read the buffer and updating GL_TEXTURE_2D
void playCache()
{
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, data.codec_ctx->width,
data.codec_ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
cache[temp]->data[0]);
temp++;
}
The issue i am facing is that when i try to read the Cached data the application crashes.
You are storing dead reference in your cache.
cache.push_back(av_frame_clone(data.gl_frame));
the doc says:
av_frame_clone: Create a new frame that references the same data as src.
When you destroy src, you loose its content and you can't access it in your cache.
You can try to move the ref to your new frame, or to copies its value.
Move:
AVFrame* cachedValue;
av_frame_move_ref(cachedValue, data.gl_frame);
cache.push_back(cachedValue);
Copy
AVFrame *cachedValue= av_frame_alloc();
cachedValue->format = data.gl_frame->format;
cachedValue->width = data.gl_frame->width;
cachedValue->height = data.gl_frame->height;
cachedValue->channels = data.gl_frame->channels;
cachedValue->channel_layout = data.gl_frame->channel_layout;
cachedValue->nb_samples = data.gl_frame->nb_samples;
av_frame_get_buffer(cachedValue, 32);
av_frame_copy(cachedValue, data.gl_frame);
av_frame_copy_props(cachedValue, data.gl_frame);
cache.push_back(cachedValue);
/////////////////////////////////////////////////
avformat_network_init();
initializeAppData();
// open video
if (avformat_open_input(&data.fmt_ctx, stdstrPathOfVideo.c_str(), NULL, NULL) < 0) {
clearAppData();
return;
}
// find stream info
if (avformat_find_stream_info(data.fmt_ctx, NULL) < 0) {
clearAppData();
return;
}
// dump debug info
// av_dump_format(data.fmt_ctx, 0, "D:\\E\\Event\\2019\\AVI_Badges\\Generic\\Generic.avi", 0);
// find the video stream
for (unsigned int i = 0; i < data.fmt_ctx->nb_streams; ++i)
{
if (data.fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
data.stream_idx = i;
break;
}
}
if (data.stream_idx == -1)
{
clearAppData();
return;
}
data.video_stream = data.fmt_ctx->streams[data.stream_idx];
data.codec_ctx = data.video_stream->codec;
// find the decoder
data.decoder = avcodec_find_decoder(data.codec_ctx->codec_id);
if (data.decoder == NULL)
{
clearAppData();
return;
}
// open the decoder
if (avcodec_open2(data.codec_ctx, data.decoder, NULL) < 0)
{
clearAppData();
return;
}
// allocate the video frames
data.av_frame = av_frame_alloc();
data.gl_frame = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_RGBA, data.codec_ctx->width,
data.codec_ctx->height);
uint8_t *internal_buffer = (uint8_t *)av_malloc(size * sizeof(uint8_t));
avpicture_fill((AVPicture *)data.gl_frame, internal_buffer, AV_PIX_FMT_RGBA,
data.codec_ctx->width, data.codec_ctx->height);
data.packet = (AVPacket *)av_malloc(sizeof(AVPacket));
I am using VS 2013 Professional in an MFC project
I have been using my software to receive data from the com port for some time, but recently needed to add transmission capability
The Init code is:
BOOL PASCAL FAR SetupConnect(pCONNECTION pCon, pCOMCONFIG pCfg)
{
DCB dcb;
pSERBUF pSB = pCon->BufStruct;
// pSERBUF *ppSB = (pSERBUF*)pCon->BufStruct;
// pSB = *ppSB;
dcb.DCBlength = sizeof(DCB);
CheckComs(); // Gets available COM ports
pCon->Port = pNames[0].PortNames[3] - 0x30;
if (pCon->BufStruct == NULL) // This is a personal Communications structure
{ // Init
pCon->hSB = GlobalAlloc(GHND, sizeof(SERBUF));
if (pCon->hSB == NULL)
{
// return INVALID_HANDLE_VALUE;
return 0;
}
pSB = (pSERBUF)GlobalLock(pCon->hSB);
pSB->idComDev = INVALID_HANDLE_VALUE;
pCon->BufStruct = pSB;
}
else return (0);
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
pSB->idComDev = CreateFile(pNames[0].PortNames, GENERIC_READ | GENERIC_WRITE,
0, //exclusive access
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
}
// Current configuration
GetCommState(pSB->idComDev, &dcb);
// Setup baudrate, parity, etc.
dcb.BaudRate = pCfg->dwBaudRate;
dcb.ByteSize = pCfg->bDataBits;
dcb.Parity = pCfg->bParity;
dcb.StopBits = pCfg->bStopBits;
// Setup Flow Control
dcb.fOutxDsrFlow = pCfg->handshake_DTR;
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR high while port open
dcb.fOutxCtsFlow = pCfg->handshake_RTS;
dcb.fRtsControl = RTS_CONTROL_DISABLE; // Toggle RTS with EscapeCommFunction
// XON/XOFF Not Used
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fBinary = TRUE;
dcb.fParity = TRUE;
//return TRUE if everything looks cool
return (SetCommState(pSB->idComDev, &dcb));
}
And:
CSerCom::CSerCom()
{
pCon = &Con;
pCfg = &Cfg;
m_SerHwnd = this;
pCfg->dwBaudRate = 115200;
pCfg->bDataBits = 8;
pCfg->bParity = NOPARITY;
pCfg->bStopBits = TWOSTOPBITS;
// here
SetupConnect(pCon, pCfg);
pSERBUF pSB = pCon->BufStruct; // pSB is set in SetUpConnect
if (pSB->idComDev == INVALID_HANDLE_VALUE)
{
// device open failure
// hardware not there or someone else controls it!
GlobalUnlock(pCon->hSB);
GlobalFree(pCon->hSB);
pCon->BufStruct = NULL;
// TODO stop this from going any further
HandleFailure();
}
else // Only continue if Port is available
{
// Clear Buffer
SetupComm(pSB->idComDev, 4096, 4096);
PurgeComm(pSB->idComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
// create the overlapped events
memset(&(pSB->osRead), 0, sizeof(OVERLAPPED));
memset(&(pSB->osWrite), 0, sizeof(OVERLAPPED));
pSB->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pSB->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if ((pSB->osRead.hEvent == NULL) || (pSB->osWrite.hEvent == NULL))
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
// allocate & lock the mem
// (used to contain data points to & from the MODBUS
// as well as the receive buffer for incoming serial data)
pSB->hRcv = GlobalAlloc(GHND, MAX_RX_LEN);
if (pSB->hRcv == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pRcv = (char *)GlobalLock(pSB->hRcv);
pSB->hTx = (char *)GlobalAlloc(GHND, MAX_TX_LEN);
if (pSB->hTx == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
pSB->pTx = (char *)GlobalLock(pSB->hTx);
// remember the setup params
pSB->TimeOut = 3; //CalculateTimeOut(pCfg->dwBaudRate);
// pSB->TimerId = TimerId;
// initialize the status counters
// pSB->ValidCt = 0;
// pSB->InvalidCt = 0;
pSB->RxInIdx = 0;
// pSB->RTS_Delay[0] = pCfg->RTS_Delay[0];
// pSB->RTS_Delay[1] = pCfg->RTS_Delay[1];
pSB->RTS_Delay[0] = 100;
pSB->RTS_Delay[1] = 100;
// setup the Comm Timeouts
CommTimeOuts.ReadIntervalTimeout = 0xffffffff;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 1000;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 1000;
SetCommTimeouts(pSB->idComDev, &CommTimeOuts);
// if everything looks good to here
// create the Receive Thread & return the CONNECT handle
pSB->hIOThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)SerProc,
(LPVOID)pCon,
0,
&dwThreadID);
if (pSB->hIOThread == NULL)
{
ReleaseNetResources(pCon);
CloseHandle(pSB->idComDev);
pSB->idComDev = INVALID_HANDLE_VALUE;
HandleFailure();
// return (pSB->idComDev);
}
hIOT = pSB->hIOThread;
}
}
So with that set up, I enter a thread loop in which I have the following
// wait indefinitely for somthing to happen
WaitCommEvent(pSB->idComDev, &dwEvtMask, NULL);
// Catch Rx event
if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
{
Edit1_txt.Format(_T("Rx'd"));
E1->SetWindowText(Edit1_txt);
CMFCView->UpdateWindow();
// only try to read number of bytes in queue
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
dwLength = ComStat.cbInQue;
// Read data bytes into connection Rcv Buffer at current RxInIdx
if (dwLength > 0)
{
fReadStat = ReadFile(pSB->idComDev,
&(pSB->pRcv[pSB->RxInIdx]),
dwLength,
&bytesread,
&(pSB->osRead));
if (!fReadStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
// We have to wait for read to complete.
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osRead), &bytesread, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
else
{
// some other error occurred
dwLength = 0;
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
} // End of Read Error
} // End of Read Char
if (ComStat.cbInQue < 500)
{
// update the receive index
pSB->RxInIdx += dwLength;
wSleepime = GetTickCount(); // hkk 7/16/99 for console app
ParseAPI(pSB);
}
else
ComStat.cbInQue = 0;
}
// At some point in the program pSB->TxOutIdx is set to some positive value
if (pSB->TxOutIdx > 0)
{
dwLength = pSB->TxOutIdx;
fWriteStat = WriteFile(pSB->idComDev,
&(pSB->pTx[pSB->TxOutIdx]),
dwLength,
&byteswritten,
&(pSB->osWrite));
if (!fWriteStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
while (!GetOverlappedResult(pSB->idComDev,
&(pSB->osWrite), &byteswritten, FALSE))
{
dwErrorFlags = GetLastError();
if (dwErrorFlags != ERROR_IO_INCOMPLETE)
// an error occurred, try to recover
ClearCommError(pSB->idComDev, &dwErrorFlags, &ComStat);
}
}
pSB->TxOutIdx -= byteswritten;
}
}
}
This detects the Tx buffer full, (pSB->TxOutIdx > 0)
and transmits the data
The transmit fails with an IO pending error, but after execution of GetOverlappedResult, bytes written show the length desired.
However, no data comes out the port. I have checked, and the port found and used is correct.
Wassup?
I would like to ask a question about ffmpeg when i use encoder (x264).
this is my code :
int
FFVideoEncoder::init(AVCodecID codecId, int bitrate, int fps, int gopSize,
int width, int height, AVPixelFormat format) {
release();
const AVCodec *codec = avcodec_find_encoder(codecId);
m_pCodecCtx = avcodec_alloc_context3(codec);
m_pCodecCtx->width = width;
m_pCodecCtx->height = height;
m_pCodecCtx->pix_fmt = format;
m_pCodecCtx->bit_rate = bitrate;
m_pCodecCtx->thread_count = 5;
m_pCodecCtx->max_b_frames = 0;
m_pCodecCtx->gop_size = gopSize;
m_pCodecCtx->time_base.num = 1;
m_pCodecCtx->time_base.den = fps;
//H.264
if (m_pCodecCtx->codec_id == AV_CODEC_ID_H264) {
// av_dict_set(&opts, "preset", "slow", 0);
av_dict_set(&m_pEncoderOpts, "preset", "superfast", 0);
av_dict_set(&m_pEncoderOpts, "tune", "zerolatency", 0);
m_pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
m_pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
int ret = avcodec_open2(m_pCodecCtx, m_pCodecCtx->codec, &m_pEncoderOpts);
if (ret == 0) {
LOGI("open avcodec success!");
} else {
LOGE("open avcodec error!");
return -1;
}
return ret;
}
int FFVideoEncoder::encode(const Frame &inFrame, AVPacket *outPacket) {
AVFrame *frame = av_frame_alloc();
// avpicture_fill((AVPicture *) frame, inFrame.getData(), AV_PIX_FMT_YUV420P, inFrame.getWidth(),
// inFrame.getHeight());
av_image_fill_arrays(frame->data, frame->linesize, inFrame.getData(), m_pCodecCtx->pix_fmt,
inFrame.getWidth(), inFrame.getHeight(), 1);
int ret = 0;
ret = avcodec_send_frame(m_pCodecCtx, frame);
if (ret != 0) {
LOGE("send frame error! %s", av_err2str(ret));
} else {
ret = avcodec_receive_packet(m_pCodecCtx, outPacket);
LOGI("extract data size = %d", m_pCodecCtx->extradata_size);
if (ret != 0) {
LOGE("receive packet error! %s", av_err2str(ret));
}
};
av_frame_free(&frame);
return ret;
}
I expect that the AVPacket will carry the pts and dts about this frame.
but in fact, i only can get encoded frame data and size.
//====================================
except this question, i have another quesiont:
x264 docs say that "tune" opts can be set like film、animation and others. but i only can get a normal video when i set "zerolatency" params. When i set others opts, video's bitrate is very low.
Thanks your answer.
This is for simple example to see if it works:
I believe you should set frame->pts beforehand.
Try this:
Set frame->pts = framecount before sending to ret = avcodec_send_frame(m_pCodecCtx, frame)
Add this framecount as a simple counter of frames you send for encode. Increases each time.
Hope that helps.