ESP32-cam with servo control won't work. Arduino IDE - esp32

I've an ESP32-cam and want to controll a servo. My code compiled without error but doesn't work.
There are two files involved, a .ino and a .cpp. The .ino seems to work right because the servo contributes to his start position 90° at startup but When i want to turn it right or left, nothing happens. This part is controlled in the .cpp and i've spend a lot of time to figure out what went wrong here without success. Any help is highly appreciated.
.ino
#include "esp_camera.h"
#include <WiFiMulti.h>
#include <Servo.h>
Servo myservo;
WiFiMulti wifiMulti;
int ledPin = 4;
#define CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// GPIO Setting
int servoPin = 2;
int posDegrees = 90; //servo initial position 90°
int posDegreesStep = 30;
extern String WiFiAddr ="";
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
myservo.attach(servoPin, 2, 0, 180); //(pin, channel, min, max) degrees
myservo.write(posDegrees);
pinMode(servoPin , OUTPUT );
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//init with high specs to pre-allocate larger buffers
if(psramFound()){
config.frame_size = FRAMESIZE_SXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
//drop down frame size for higher initial frame rate
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_CIF);
wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");
wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_2");
//wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");
Serial.println("Connecting Wifi...");
if (wifiMulti.run() == WL_CONNECTED) {
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
}
startCameraServer();
Serial.print("Camera Ready!");
Serial.print(WiFi.localIP());
WiFiAddr = WiFi.localIP().toString();
Serial.println("' to connect");
}
void wifireconnect() {
if (wifiMulti.run() != WL_CONNECTED) {
Serial.println("WiFi not connected!");
delay(500);
WiFi.disconnect();
Serial.println("\nReboot");
ESP.restart();
}
}
void loop() {
wifireconnect();
}
.cpp
#include "esp_http_server.h"
#include "esp_timer.h"
#include "esp_camera.h"
#include "img_converters.h"
#include "camera_index.h"
#include "Arduino.h"
#include "Servo.h"
extern int servoPin;
extern int posDegrees;
extern int posDegreesStep;
extern String WiFiAddr;
typedef struct {
size_t size;
size_t index;
size_t count;
int sum;
int * values;
} ra_filter_t;
typedef struct {
httpd_req_t *req;
size_t len;
} jpg_chunking_t;
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
static ra_filter_t ra_filter;
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;
static ra_filter_t * ra_filter_init(ra_filter_t * filter, size_t sample_size) {
memset(filter, 0, sizeof(ra_filter_t));
filter->values = (int *)malloc(sample_size * sizeof(int));
if (!filter->values) {
return NULL;
}
memset(filter->values, 0, sample_size * sizeof(int));
filter->size = sample_size;
return filter;
}
static int ra_filter_run(ra_filter_t * filter, int value) {
if (!filter->values) {
return value;
}
filter->sum -= filter->values[filter->index];
filter->values[filter->index] = value;
filter->sum += filter->values[filter->index];
filter->index++;
filter->index = filter->index % filter->size;
if (filter->count < filter->size) {
filter->count++;
}
return filter->sum / filter->count;
}
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len) {
jpg_chunking_t *j = (jpg_chunking_t *)arg;
if (!index) {
j->len = 0;
}
if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) {
return 0;
}
j->len += len;
return len;
}
static esp_err_t capture_handler(httpd_req_t *req) {
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
int64_t fr_start = esp_timer_get_time();
fb = esp_camera_fb_get();
if (!fb) {
Serial.printf("Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
size_t fb_len = 0;
if (fb->format == PIXFORMAT_JPEG) {
fb_len = fb->len;
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
esp_camera_fb_return(fb);
int64_t fr_end = esp_timer_get_time();
Serial.printf("JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
return res;
}
static esp_err_t stream_handler(httpd_req_t *req) {
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
static int64_t last_frame = 0;
if (!last_frame) {
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK) {
return res;
}
while (true) {
fb = esp_camera_fb_get();
if (!fb) {
Serial.printf("Camera capture failed");
res = ESP_FAIL;
} else {
if (fb->format != PIXFORMAT_JPEG) {
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if (!jpeg_converted) {
Serial.printf("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
if (res == ESP_OK) {
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK) {
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (res == ESP_OK) {
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if (fb) {
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if (_jpg_buf) {
free(_jpg_buf);
_jpg_buf = NULL;
}
if (res != ESP_OK) {
break;
}
int64_t fr_end = esp_timer_get_time();
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
//Serial.printf("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)"
// ,(uint32_t)(_jpg_buf_len),
// (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
// avg_frame_time, 1000.0 / avg_frame_time
//);
}
last_frame = 0;
return res;
}
static esp_err_t cmd_handler(httpd_req_t *req) {
char* buf;
size_t buf_len;
char variable[32] = {0,};
char value[32] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if (!buf) {
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int val = atoi(value);
sensor_t * s = esp_camera_sensor_get();
int res = 0;
if (!strcmp(variable, "framesize")) {
if (s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
}
else if (!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if (!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
else if (!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
else if (!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
else if (!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val);
else if (!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val);
else if (!strcmp(variable, "awb")) res = s->set_whitebal(s, val);
else if (!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val);
else if (!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val);
else if (!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
else if (!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
else if (!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val);
else if (!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val);
else if (!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val);
else if (!strcmp(variable, "aec2")) res = s->set_aec2(s, val);
else if (!strcmp(variable, "dcw")) res = s->set_dcw(s, val);
else if (!strcmp(variable, "bpc")) res = s->set_bpc(s, val);
else if (!strcmp(variable, "wpc")) res = s->set_wpc(s, val);
else if (!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val);
else if (!strcmp(variable, "lenc")) res = s->set_lenc(s, val);
else if (!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val);
else if (!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
else if (!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
else {
res = -1;
}
if (res) {
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
static esp_err_t status_handler(httpd_req_t *req) {
static char json_response[1024];
sensor_t * s = esp_camera_sensor_get();
char * p = json_response;
*p++ = '{';
p += sprintf(p, "\"framesize\":%u,", s->status.framesize);
p += sprintf(p, "\"quality\":%u,", s->status.quality);
p += sprintf(p, "\"brightness\":%d,", s->status.brightness);
p += sprintf(p, "\"contrast\":%d,", s->status.contrast);
p += sprintf(p, "\"saturation\":%d,", s->status.saturation);
p += sprintf(p, "\"special_effect\":%u,", s->status.special_effect);
p += sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode);
p += sprintf(p, "\"awb\":%u,", s->status.awb);
p += sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain);
p += sprintf(p, "\"aec\":%u,", s->status.aec);
p += sprintf(p, "\"aec2\":%u,", s->status.aec2);
p += sprintf(p, "\"ae_level\":%d,", s->status.ae_level);
p += sprintf(p, "\"aec_value\":%u,", s->status.aec_value);
p += sprintf(p, "\"agc\":%u,", s->status.agc);
p += sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain);
p += sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling);
p += sprintf(p, "\"bpc\":%u,", s->status.bpc);
p += sprintf(p, "\"wpc\":%u,", s->status.wpc);
p += sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma);
p += sprintf(p, "\"lenc\":%u,", s->status.lenc);
p += sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
p += sprintf(p, "\"dcw\":%u,", s->status.dcw);
p += sprintf(p, "\"colorbar\":%u", s->status.colorbar);
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, strlen(json_response));
}
static esp_err_t index_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "text/html");
String page = "";
page += "<meta name=\"viewport\" content=\"width=device-width\">\n";
page += "<p><h2></h2></p><br/><br/><br/>";
page += "<script>var xhttp = new XMLHttpRequest();</script>";
page += "<script>function getsend(arg) { xhttp.open('GET', arg +'?' + new Date().getTime(), true); xhttp.send() } </script>";
//page += "<p align=center><IMG SRC='http://" + WiFiAddr + ":81/stream' style='width:280px;'></p><br/><br/>";
page += "<p align=center><IMG SRC='http://" + WiFiAddr + ":81/stream' style='width:600px; transform:rotate(0deg);'></p><br/>";
//page += "<p align=center> <button style=width:90px;height:80px onmousedown=getsend('go') onmouseup=getsend('stop') ontouchstart=getsend('go') ontouchend=getsend('stop') ></button> </p>";
//page += "<p align=center>";
//page += "<button style=width:90px;height:80px onmousedown=getsend('left') onmouseup=getsend('stop') ontouchstart=getsend('left') ontouchend=getsend('stop')></button> ";
//page += "<button style=width:90px;height:80px onmousedown=getsend('stop') onmouseup=getsend('stop')></button> ";
//page += "<button style=width:90px;height:80px onmousedown=getsend('right') onmouseup=getsend('stop') ontouchstart=getsend('right') ontouchend=getsend('stop')></button>";
//page += "</p>";
//page += "<p align=center><button style=width:90px;height:80px onmousedown=getsend('back') onmouseup=getsend('stop') ontouchstart=getsend('back') ontouchend=getsend('stop') ></button></p>";
page += "<p align=center><br/><br/>";
page += "<button style=width:120px;height:40px;background:#768d87 onmousedown=getsend('links')>links</button> ";
page += "<button style=width:150px;height:40px;background:#91b8b3 onmousedown=getsend('reboot')>ESP Restart</button> ";
page += "<button style=width:120px;height:40px;background:#768d87 onmousedown=getsend('rechts')>rechts</button>";
page += "</p>";
return httpd_resp_send(req, &page[0], strlen(&page[0]));
}
static esp_err_t reboot_handler(httpd_req_t *req) {
delay(500);
Serial.println("rebooting");
delay(2000);
ESP.restart();
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, "OK", 2);
}
static esp_err_t links_handler(httpd_req_t *req) {
Servo myservo;
if (posDegrees >= 0 && posDegrees <= 180) {
posDegrees = posDegrees + posDegreesStep;
}
if (posDegrees > 180) {
posDegrees = 180;
}
else {
myservo.write(posDegrees); // move the servo to calculated angle
Serial.print("Moved to: ");
Serial.print(posDegrees); // print the angle
Serial.println(" degree");
}
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, "OK", 2);
}
static esp_err_t rechts_handler(httpd_req_t *req) {
Servo myservo;
if (posDegrees > 0 && posDegrees <= 180) {
posDegrees = posDegrees - posDegreesStep;
}
if (posDegrees < 0) {
posDegrees = 0;
} else {
myservo.write(posDegrees); // move the servo to calculated angle
Serial.print("Moved to: ");
Serial.print(posDegrees); // print the angle
Serial.println(" degree");
}
httpd_resp_set_type(req, "text/html");
return httpd_resp_send(req, "OK", 2);
}
void startCameraServer() {
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
httpd_uri_t reboot_uri = {
.uri = "/reboot",
.method = HTTP_GET,
.handler = reboot_handler,
.user_ctx = NULL
};
httpd_uri_t links_uri = {
.uri = "/links",
.method = HTTP_GET,
.handler = links_handler,
.user_ctx = NULL
};
httpd_uri_t rechts_uri = {
.uri = "/rechts",
.method = HTTP_GET,
.handler = rechts_handler,
.user_ctx = NULL
};
httpd_uri_t index_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = index_handler,
.user_ctx = NULL
};
httpd_uri_t status_uri = {
.uri = "/status",
.method = HTTP_GET,
.handler = status_handler,
.user_ctx = NULL
};
httpd_uri_t cmd_uri = {
.uri = "/control",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_uri_t capture_uri = {
.uri = "/capture",
.method = HTTP_GET,
.handler = capture_handler,
.user_ctx = NULL
};
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
ra_filter_init(&ra_filter, 20);
Serial.printf("Starting web server on port: '%d'", config.server_port);
if (httpd_start(&camera_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(camera_httpd, &index_uri);
httpd_register_uri_handler(camera_httpd, &reboot_uri);
httpd_register_uri_handler(camera_httpd, &links_uri);
httpd_register_uri_handler(camera_httpd, &rechts_uri);
} else {
Serial.printf("Starting web server failed");
}
config.server_port += 1;
config.ctrl_port += 1;
Serial.printf("Starting stream server on port: '%d'", config.server_port);
if (httpd_start(&stream_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(stream_httpd, &stream_uri);
}
}

I had the exact same issue. It's probably because the timers for the camera are interfering with the servo timers. You have to use this library, ServoESP32, and attach your servo like this:
Servo remote;
remote.attach(16, 2);
All this does is attach your servo to channel 2 given that channels 0 and 1 are being used by the CAM. I tried this and it fixed the problem instantly.

Related

ffmpeg avcodec_encode_video2 hangs when using Quick Sync h264_qsv encoder

When I use the mpeg4 or h264 encoders, I am able to successfully encode images to make a valid AVI file using the API for ffmpeg 3.1.0. However, when I use the Quick Sync encoder (h264_qsv), avcodec_encode_video2 will hang some of the time. I found that when using images that are 1920x1080, it was rare that avcodec_encode_video2 would hang. When using 256x256 images, it was very likely that the function would hang.
I have created the test code below that demonstrates the hang of avcodec_encode_video2. The code will create a 1000 frame, 256x256 AVI with a bit rate of 400000. The frames are simply allocated, so the output video should just be green frames.
The problem was observed using Windows 7 and Windows 10, using the 32-bit or 64-bit test application.
If anyone has any idea on how I can avoid the avcodec_encode_video2 hang I would be very grateful! Thanks in advance for any assistance.
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"
#include "avutil.h"
#include "imgutils.h"
#include "opt.h"
#include <rational.h>
}
#include <iostream>
// Globals
AVCodec* m_pCodec = NULL;
AVStream *m_pStream = NULL;
AVOutputFormat* m_pFormat = NULL;
AVFormatContext* m_pFormatContext = NULL;
AVCodecContext* m_pCodecContext = NULL;
AVFrame* m_pFrame = NULL;
int m_frameIndex;
// Output format
AVPixelFormat m_pixType = AV_PIX_FMT_NV12;
// Use for mpeg4
//AVPixelFormat m_pixType = AV_PIX_FMT_YUV420P;
// Output frame rate
int m_frameRate = 30;
// Output image dimensions
int m_imageWidth = 256;
int m_imageHeight = 256;
// Number of frames to export
int m_frameCount = 1000;
// Output file name
const char* m_fileName = "c:/test/test.avi";
// Output file type
const char* m_fileType = "AVI";
// Codec name used to encode
const char* m_encoderName = "h264_qsv";
// use for mpeg4
//const char* m_encoderName = "mpeg4";
// Target bit rate
int m_targetBitRate = 400000;
void addVideoStream()
{
m_pStream = avformat_new_stream( m_pFormatContext, m_pCodec );
m_pStream->id = m_pFormatContext->nb_streams - 1;
m_pStream->time_base = m_pCodecContext->time_base;
m_pStream->codec->pix_fmt = m_pixType;
m_pStream->codec->flags = m_pCodecContext->flags;
m_pStream->codec->width = m_pCodecContext->width;
m_pStream->codec->height = m_pCodecContext->height;
m_pStream->codec->time_base = m_pCodecContext->time_base;
m_pStream->codec->bit_rate = m_pCodecContext->bit_rate;
}
AVFrame* allocatePicture( enum AVPixelFormat pix_fmt, int width, int height )
{
AVFrame *frame;
frame = av_frame_alloc();
if ( !frame )
{
return NULL;
}
frame->format = pix_fmt;
frame->width = width;
frame->height = height;
int checkImage = av_image_alloc( frame->data, frame->linesize, width, height, pix_fmt, 32 );
if ( checkImage < 0 )
{
return NULL;
}
return frame;
}
bool initialize()
{
AVRational frameRate;
frameRate.den = m_frameRate;
frameRate.num = 1;
av_register_all();
m_pCodec = avcodec_find_encoder_by_name(m_encoderName);
if( !m_pCodec )
{
return false;
}
m_pCodecContext = avcodec_alloc_context3( m_pCodec );
m_pCodecContext->width = m_imageWidth;
m_pCodecContext->height = m_imageHeight;
m_pCodecContext->time_base = frameRate;
m_pCodecContext->gop_size = 0;
m_pCodecContext->pix_fmt = m_pixType;
m_pCodecContext->codec_id = m_pCodec->id;
m_pCodecContext->bit_rate = m_targetBitRate;
av_opt_set( m_pCodecContext->priv_data, "+CBR", "", 0 );
return true;
}
bool startExport()
{
m_frameIndex = 0;
char fakeFileName[512];
int checkAllocContext = avformat_alloc_output_context2( &m_pFormatContext, NULL, m_fileType, fakeFileName );
if ( checkAllocContext < 0 )
{
return false;
}
if ( !m_pFormatContext )
{
return false;
}
m_pFormat = m_pFormatContext->oformat;
if ( m_pFormat->video_codec != AV_CODEC_ID_NONE )
{
addVideoStream();
int checkOpen = avcodec_open2( m_pCodecContext, m_pCodec, NULL );
if ( checkOpen < 0 )
{
return false;
}
m_pFrame = allocatePicture( m_pCodecContext->pix_fmt, m_pCodecContext->width, m_pCodecContext->height );
if( !m_pFrame )
{
return false;
}
m_pFrame->pts = 0;
}
int checkOpen = avio_open( &m_pFormatContext->pb, m_fileName, AVIO_FLAG_WRITE );
if ( checkOpen < 0 )
{
return false;
}
av_dict_set( &(m_pFormatContext->metadata), "title", "QS Test", 0 );
int checkHeader = avformat_write_header( m_pFormatContext, NULL );
if ( checkHeader < 0 )
{
return false;
}
return true;
}
int processFrame( AVPacket& avPacket )
{
avPacket.stream_index = 0;
avPacket.pts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
avPacket.dts = av_rescale_q( m_pFrame->pts, m_pStream->codec->time_base, m_pStream->time_base );
m_pFrame->pts++;
int retVal = av_interleaved_write_frame( m_pFormatContext, &avPacket );
return retVal;
}
bool exportFrame()
{
int success = 1;
int result = 0;
AVPacket avPacket;
av_init_packet( &avPacket );
avPacket.data = NULL;
avPacket.size = 0;
fflush(stdout);
std::cout << "Before avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
success = avcodec_encode_video2( m_pCodecContext, &avPacket, m_pFrame, &result );
std::cout << "After avcodec_encode_video2 for frame: " << m_frameIndex << std::endl;
if( result )
{
success = processFrame( avPacket );
}
av_packet_unref( &avPacket );
m_frameIndex++;
return ( success == 0 );
}
void endExport()
{
int result = 0;
int success = 0;
if (m_pFrame)
{
while ( success == 0 )
{
AVPacket avPacket;
av_init_packet( &avPacket );
avPacket.data = NULL;
avPacket.size = 0;
fflush(stdout);
success = avcodec_encode_video2( m_pCodecContext, &avPacket, NULL, &result );
if( result )
{
success = processFrame( avPacket );
}
av_packet_unref( &avPacket );
if (!result)
{
break;
}
}
}
if (m_pFormatContext)
{
av_write_trailer( m_pFormatContext );
if( m_pFrame )
{
av_frame_free( &m_pFrame );
}
avio_closep( &m_pFormatContext->pb );
avformat_free_context( m_pFormatContext );
m_pFormatContext = NULL;
}
}
void cleanup()
{
if( m_pFrame || m_pCodecContext )
{
if( m_pFrame )
{
av_frame_free( &m_pFrame );
}
if( m_pCodecContext )
{
avcodec_close( m_pCodecContext );
av_free( m_pCodecContext );
}
}
}
int main()
{
bool success = true;
if (initialize())
{
if (startExport())
{
for (int loop = 0; loop < m_frameCount; loop++)
{
if (!exportFrame())
{
std::cout << "Failed to export frame\n";
success = false;
break;
}
}
endExport();
}
else
{
std::cout << "Failed to start export\n";
success = false;
}
cleanup();
}
else
{
std::cout << "Failed to initialize export\n";
success = false;
}
if (success)
{
std::cout << "Successfully exported file\n";
}
return 1;
}
The problem no longer occurs now that I have updated to the latest Intel® Graphics Driver (version 15.45.10.4542)

Developing with Firefox SDK with IDE (Visual Studio 2013 maybe)

I started developing a Firefox add-on, however I could not find any IDE specifically for Firefox. For most part it doesn't really matter because I can just open Javascript files and edit them (I use VS2013 and Web Essentials (I think)).
Up to this point everything is acceptable, but when I have to use cmd every time to run this plugin and then read console logs from cmd, it becomes a nightmare.
So my is - is there some way to launch, develop and log Firefox plugin just like any code in Visual Studio 2013? Other IDEs are welcome too.
Well I think it would be possible to create Visual Studio add-on, but it just too much work. However, I managed to partly integrate Firefox add-on creation into VS2013 with c++ code. It redirects cmd window so that means, that you'll output from cmd in "Output" window while debugging.
I'm leaving complete code with steps in case someone else needs this (C++11 is required):
Create Win32 C++ project (not cmd one).
Paste code (below) into cpp file.
Change YOUR_EXTENSION_NAME to your add-on name.
Run code once, it should throw message box with info where to put Add-on SDK.
Copy SDK files to that folder.
Run code again and exit (you may exit however you want, it should terminate remaining windows).
Now there are 3 options for file (.js, .css, etc.) linking:
Create files manually in SDK folder and add them manually to project.
Create files via VS2013 menu and then uncomment and modify, add, delete lines in do while loop.
Create files via VS2013 menu, but choose SDK folders.
Code:
#include <windows.h>
#include <tchar.h>
#include <thread>
#include <chrono>
#include <typeinfo>
#include <Shlwapi.h>
#pragma comment(lib,"Shlwapi.lib")
// Timer code start
/*
//
//Credit goes to James Daughtry for this piece of code
//
*/
class Timer {
typedef std::chrono::high_resolution_clock high_resolution_clock;
typedef std::chrono::milliseconds milliseconds;
public:
Timer(bool run = false)
{
if (run) Reset();
}
void Reset()
{
_start = high_resolution_clock::now();
}
milliseconds Elapsed() const
{
return std::chrono::duration_cast<milliseconds>(high_resolution_clock::now() - _start);
}
private:
high_resolution_clock::time_point _start;
};
// Timer code end
// Cmd redirection code start
/*
//
//Credit goes to some guys from StackOverflow for directions and Randor from CodeProject for base code
//
*/
struct _JOBWRAPPER
{
HANDLE hJob;
_JOBWRAPPER() : hJob(NULL) {}
~_JOBWRAPPER() { if (this->hJob != NULL) CloseHandle(hJob); }
operator HANDLE() const { return this->hJob; }
}hJob;
typedef void(*TextOutFunction)(LPCSTR);
struct _THREADARGUMENTS
{
HANDLE hOutRead;
clock_t stTimeout;
LPCSTR pchBreakText;
TextOutFunction Function;
bool bGotInfo;
_THREADARGUMENTS() : bGotInfo(false), hOutRead(NULL), stTimeout(NULL), pchBreakText(nullptr), Function(nullptr) {}
};
void ReadCMDThread(_THREADARGUMENTS* Arguments)
{
if (Arguments->hOutRead != NULL)
{
UINT CheckForAnyResponseOnLoop = 5, CurrentLoop = 0;
clock_t ScanInterval = 50;
DWORD dwAvailable = 0;
DWORD bytesRead = 0;
CHAR szOut[4096] = { 0 };
if (Arguments->stTimeout == 0)
{
while (true)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
else
{
Timer timer(true);
while (timer.Elapsed() < (std::chrono::milliseconds)Arguments->stTimeout)
{
CurrentLoop++;
PeekNamedPipe(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, &dwAvailable, NULL);
if (0 != bytesRead)
{
if (ReadFile(Arguments->hOutRead, szOut, sizeof(szOut), &bytesRead, NULL))
Arguments->bGotInfo = true;
Arguments->Function(szOut);
timer.Reset();
if (Arguments->pchBreakText != nullptr && Arguments->pchBreakText != "" && strstr(szOut, Arguments->pchBreakText) != nullptr)
break;
memset(szOut, '\0', sizeof(char) * 4096);
}
if (CheckForAnyResponseOnLoop == CurrentLoop && Arguments->pchBreakText == "")
break;
std::this_thread::sleep_for((std::chrono::milliseconds)ScanInterval);
}
}
}
}
class CMDREDIRECTION{
private:
HANDLE hInRead, hInWrite, hOutRead, hOutWrite;
PROCESS_INFORMATION pi;
STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
TextOutFunction CustomFunction;
public:
CMDREDIRECTION(TextOutFunction Function) : hInRead(NULL), hInWrite(NULL), hOutRead(NULL),
hOutWrite(NULL), CustomFunction(Function) {}
~CMDREDIRECTION(){
if (hInRead != NULL)
CloseHandle(hInRead);
if (hInWrite != NULL)
CloseHandle(hInWrite);
if (hOutRead != NULL)
CloseHandle(hOutRead);
if (hOutWrite != NULL)
CloseHandle(hOutWrite);
}
DWORD WriteToCmd(LPSTR pchString, bool PressEnter = false)
{
DWORD dwWritten = 0;
size_t GivenStringLength = strlen(pchString);
LPSTR TemporaryString = pchString;
bool bSuccess = false;
if (GivenStringLength != 0)
{
if (PressEnter)
{
size_t StringSize = GivenStringLength + 2;
TemporaryString = new CHAR[StringSize];
for (size_t i = 0; i < GivenStringLength; i++)
TemporaryString[i] = pchString[i];
TemporaryString[StringSize - 2] = '\n';
TemporaryString[StringSize - 1] = '\0';
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
delete[] TemporaryString;
}
else
bSuccess = (WriteFile(hInWrite, TemporaryString, strlen(TemporaryString), &dwWritten, NULL) && dwWritten);
}
return bSuccess;
}
bool GetAnswer(clock_t stTimeout, LPCSTR pchBreakText)
{
_THREADARGUMENTS Arguments;
Arguments.hOutRead = hOutRead;
Arguments.pchBreakText = pchBreakText;
Arguments.stTimeout = stTimeout;
Arguments.Function = CustomFunction;
std::thread CMDWatcher(ReadCMDThread, &Arguments);
CMDWatcher.join();
return Arguments.bGotInfo;
}
bool WriteToCmdAndWaitForAnswer(LPSTR pchString, clock_t stTimeout, LPCSTR pchBreakText, bool PressEnter = false)
{
if (WriteToCmd(pchString, PressEnter))
{
return (GetAnswer(stTimeout, pchBreakText));
}
else
{
return false;
}
}
bool Start()
{
if (hJob.hJob == NULL)
{
hJob.hJob = CreateJobObject(NULL, NULL);
if (hJob.hJob != NULL)
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject((HANDLE)hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
return false;
}
}
else
{
return false;
}
}
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
CreatePipe(&hInRead, &hInWrite, &sa, 0);
CreatePipe(&hOutRead, &hOutWrite, &sa, 0);
ZeroMemory(&si, sizeof(si));
GetStartupInfo(&si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdOutput = hOutWrite;
si.hStdError = hOutWrite;
si.hStdInput = hInRead;
si.wShowWindow = SW_HIDE;
TCHAR Path[MAX_PATH] = { 0 };
GetSystemDirectory(Path, MAX_PATH);
_tcscat_s(Path, TEXT("\\cmd.exe"));
if (CreateProcess(Path, NULL, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
BOOL bResult = AssignProcessToJobObject(hJob, pi.hProcess);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return (bResult != 0);
}
else
{
return false;
}
}
};
// Cmd redirection code end
// TString code start
#ifdef UNICODE
#define TCat TCatW
#define TString _TString<WCHAR>
#else
#define TCat TCatA
#define TString _TString<CHAR>
#endif
struct AnyString
{
PVOID String;
bool bWide;
AnyString(LPSTR String)
{
this->String = String;
bWide = false;
}
AnyString(LPWSTR String)
{
this->String = String;
bWide = true;
}
operator LPSTR() { return (LPSTR)String; }
operator LPSTR() const { return (LPSTR)String; }
operator LPWSTR() { return (LPWSTR)String; }
operator LPWSTR() const { return (LPWSTR)String; }
};
template<class T>
class _TString
{
friend void SeAnyString(LPSTR String, _TString<CHAR> &TempString);
T *String;
size_t size;
void free()
{
if (String != nullptr && size != 0)
{
delete[] String;
String = nullptr;
size = 0;
}
}
_TString<CHAR> ToCHAR(LPWSTR wch)
{
_TString<CHAR> TempString;
LPSTR Buffer = nullptr;
size_t size = wcslen(wch),
realsize = size + 1;
if (size != 0)
{
Buffer = new CHAR[realsize];
wcstombs_s(nullptr, Buffer, realsize, wch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
_TString<WCHAR> ToWCHAR(LPSTR ch)
{
_TString<WCHAR> TempString;
LPWSTR Buffer = nullptr;
size_t size = strlen(ch),
realsize = size + 1;
if (size != 0)
{
Buffer = new WCHAR[realsize];
mbstowcs_s(nullptr, Buffer, realsize, ch, size);
TempString.SetAllocatedString(Buffer, size);
}
return TempString;
}
public:
_TString(T *String)
{
free();
if (typeid(T) == typeid(CHAR))
{
size = strlen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = '\0';
}
}
else if (typeid(T) == typeid(WCHAR))
{
size = wcslen(String);
if (size != 0)
{
this->String = new T[size + 1];
for (size_t i = 0; i < size; i++)
this->String[i] = String[i];
this->String[size] = L'\0';
}
}
}
_TString() : String(nullptr), size(0) {}
~_TString() { free(); }
_TString(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
}
_TString& operator=(_TString&& OldTempStr)
{
this->String = OldTempStr.String;
this->size = OldTempStr.size;
OldTempStr.size = 0;
OldTempStr.String = nullptr;
return *this;
}
operator T*() const { return String; }
operator T*() { return String; }
T& operator[] (size_t i) { return String[i]; }
void SetAllocatedString(T *String, size_t size)
{
free();
this->String = String;
this->size = size;
}
void join(LPWSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(LPSTR StringToJoin)
{
join(AnyString(StringToJoin));
}
void join(AnyString StringToJoin)
{
if (typeid(T) == typeid(CHAR))
{
size_t length = 0;
_TString<CHAR> TempString;
LPSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
TempString = ToCHAR(StringToJoin);
StringLiteral = TempString;
}
else
{
StringLiteral = StringToJoin;
}
if (StringLiteral != nullptr)
length = strlen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = '\0';
free();
size = newsize;
String = Buffer;
}
}
else if (typeid(T) == typeid(WCHAR))
{
size_t length = 0;
_TString<WCHAR> TempString;
LPWSTR StringLiteral = nullptr;
if (StringToJoin.bWide)
{
StringLiteral = StringToJoin;
}
else
{
TempString = ToWCHAR(StringToJoin);
StringLiteral = TempString;
}
if (StringLiteral != nullptr)
length = wcslen(StringLiteral);
if (length != 0)
{
size_t newsize = size + length, realsize = newsize + 1;
T *Buffer = new T[realsize];
for (size_t i = 0; i < size; i++)
Buffer[i] = String[i];
for (size_t i = size, j = 0; i < newsize; i++, j++)
Buffer[i] = StringLiteral[j];
Buffer[newsize] = L'\0';
free();
size = newsize;
String = Buffer;
}
}
}
size_t GetSize() { return size; }
T* GetString() { return String; }
};
_TString<CHAR> TCatA(std::initializer_list<AnyString> list)
{
_TString<CHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
_TString<WCHAR> TCatW(std::initializer_list<AnyString> list)
{
_TString<WCHAR> String;
for (auto iterator = list.begin(), end = list.end(); iterator != end; ++iterator)
String.join(*iterator);
return String;
}
// TString code end
// Main code start
#define EXTENSION_NAME YOUR_EXTENSION_NAME //"my-extension" in ANSI
void WriteToOutputWindow(LPCSTR Text) { OutputDebugStringA(Text); }
void GetProjectDirectory(TString &Path)
{
TCHAR MaxPath[MAX_PATH] = { 0 };
GetModuleFileName(NULL, MaxPath, MAX_PATH);
for (int i = _tcslen(MaxPath), ch = 0; i > 0; i--)
{
if (MaxPath[i] == TEXT('\\') && ++ch == 2)
break;
else
MaxPath[i] = TEXT('\0');
}
Path.join(MaxPath);
}
void GetDataDirectory(TString &Path)
{
GetProjectDirectory(Path);
TCHAR TempBuffer[MAX_PATH] = { 0 }, FinalBuffer[MAX_PATH] = { 0 };
for (size_t i = Path.GetSize() - 1, ch = 0, j = 0; i > 0; i--, j++)
{
if (Path[i] == TEXT('\\') && ++ch == 2)
break;
else
TempBuffer[j] = Path[i];
}
for (size_t i = _tcslen(TempBuffer), j = 0; i > 0; i--, j++)
FinalBuffer[j] = TempBuffer[i - 1];
Path.join(FinalBuffer);
}
bool Restart()
{
int msgboxID = MessageBox(NULL, TEXT("Firefox has been closed. Save changes and press \"Yes\" to run again."), TEXT("Run again?"), MB_YESNO | MB_ICONQUESTION);
switch (msgboxID)
{
case IDYES:
return true;
case IDNO:
return false;
}
}
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrev, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
CMDREDIRECTION Window(WriteToOutputWindow);
TString ExtensionDir;
TString DataDir;
if (Window.Start())
{
GetProjectDirectory(ExtensionDir);
GetDataDirectory(DataDir);
ExtensionDir.join(TEXT("Firefox SDK\\"));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir \"", ExtensionDir.GetString(), "\"" }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
{
MessageBox(NULL, TCat({ TEXT("Firefox SDK directory is empty, please copy SDK files to this directory: "), ExtensionDir.GetString() }), TEXT("Failure!"), MB_ICONINFORMATION);
return EXIT_FAILURE;
}
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", ExtensionDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer("bin\\activate", 0, "", true);
ExtensionDir.join(TCat({ TEXT(EXTENSION_NAME), TEXT("\\") }));
if (!PathIsDirectory(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer(TCatA({ "mkdir ", EXTENSION_NAME }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", EXTENSION_NAME }), 0, "", true);
if (PathIsDirectoryEmpty(ExtensionDir))
Window.WriteToCmdAndWaitForAnswer("cfx init", 0, "", true);
do
{
/*
Window.WriteToCmdAndWaitForAnswer(TCatA({ "cd ", DataDir.GetString() }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"main.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\lib\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.js\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y /EXCLUDE:exclude.txt" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.html\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.png\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
Window.WriteToCmdAndWaitForAnswer(TCatA({ "XCOPY \"*.css\" \"", ExtensionDir.GetString(), TEXT(EXTENSION_NAME), "\\data\\\" /Y" }), 0, "", true);
*/
Window.WriteToCmdAndWaitForAnswer("cfx run --profiledir=\"./dir\"", 0, "Program terminated successfully.", true);
} while (Restart());
}
return EXIT_SUCCESS;
}
// Main code end

how to convert an MPEGTS file into an FLV file by programming with libavcodec

I wanna convert an MPEGTS file into an FLV file with libavcodec APIs(just transformat, video/audio codecs are not changed). Following is the code I found on web. After some hack, it can generate an FLV file, which could not be played. Any clue to fix this?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/rational.h>
#include <libavdevice/avdevice.h>
#include <libavutil/mathematics.h>
#include <libswscale/swscale.h>
static AVStream* add_output_stream(AVFormatContext* output_format_context, AVStream* input_stream) {
AVCodecContext* input_codec_context = NULL;
AVCodecContext* output_codec_context = NULL;
AVStream* output_stream = NULL;
output_stream = avformat_new_stream(output_format_context, 0);
if (!output_stream) {
printf("Call av_new_stream function failed\n");
return NULL;
}
input_codec_context = input_stream->codec;
output_codec_context = output_stream->codec;
output_codec_context->codec_id = input_codec_context->codec_id;
output_codec_context->codec_type = input_codec_context->codec_type;
// output_codec_context->codec_tag = input_codec_context->codec_tag;
output_codec_context->codec_tag = av_codec_get_tag(output_format_context->oformat->codec_tag, input_codec_context->codec_id);
output_codec_context->bit_rate = input_codec_context->bit_rate;
output_codec_context->extradata = input_codec_context->extradata;
output_codec_context->extradata_size = input_codec_context->extradata_size;
if (av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(input_stream->time_base) && av_q2d(input_stream->time_base) < 1.0 / 1000) {
output_codec_context->time_base = input_codec_context->time_base;
output_codec_context->time_base.num *= input_codec_context->ticks_per_frame;
} else {
output_codec_context->time_base = input_stream->time_base;
}
switch (input_codec_context->codec_type) {
case AVMEDIA_TYPE_AUDIO:
output_codec_context->channel_layout = input_codec_context->channel_layout;
output_codec_context->sample_rate = input_codec_context->sample_rate;
output_codec_context->channels = input_codec_context->channels;
output_codec_context->frame_size = input_codec_context->frame_size;
if ((input_codec_context->block_align == 1 && input_codec_context->codec_id == CODEC_ID_MP3) || input_codec_context->codec_id == CODEC_ID_AC3) {
output_codec_context->block_align = 0;
} else {
output_codec_context->block_align = input_codec_context->block_align;
}
break;
case AVMEDIA_TYPE_VIDEO:
output_codec_context->pix_fmt = input_codec_context->pix_fmt;
output_codec_context->width = input_codec_context->width;
output_codec_context->height = input_codec_context->height;
output_codec_context->has_b_frames = input_codec_context->has_b_frames;
if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
output_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
// output_codec_context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
break;
default:
break;
}
return output_stream;
}
int main(int argc, char* argv[]) {
const char* input = argv[1];
const char* output_prefix = NULL;
char* segment_duration_check = 0;
const char* index = NULL;
char* tmp_index = NULL;
const char* http_prefix = NULL;
long max_tsfiles = 0;
double prev_segment_time = 0;
double segment_duration = 0;
AVInputFormat* ifmt = NULL;
AVOutputFormat* ofmt = NULL;
AVFormatContext* ic = NULL;
AVFormatContext* oc = NULL;
AVStream* video_st = NULL;
AVStream* audio_st = NULL;
AVCodec* codec = NULL;
AVDictionary* pAVDictionary = NULL;
av_register_all();
av_log_set_level(AV_LOG_DEBUG);
char szError[256] = {0};
int nRet = avformat_open_input(&ic, input, ifmt, &pAVDictionary);
if (nRet != 0) {
av_strerror(nRet, szError, 256);
printf(szError);
printf("\n");
printf("Call avformat_open_input function failed!\n");
return 0;
}
if (avformat_find_stream_info(ic, NULL) < 0) {
printf("Call av_find_stream_info function failed!\n");
return 0;
}
ofmt = av_guess_format(NULL, argv[2], NULL);
if (!ofmt) {
printf("Call av_guess_format function failed!\n");
return 0;
}
oc = avformat_alloc_context();
if (!oc) {
printf("Call av_guess_format function failed!\n");
return 0;
}
oc->oformat = ofmt;
int video_index = -1, audio_index = -1;
unsigned int i;
for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++) {
switch (ic->streams[i]->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
video_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
video_st = add_output_stream(oc, ic->streams[i]);
if (video_st->codec->codec_id == CODEC_ID_H264) {
video_st->codec->opaque = av_bitstream_filter_init("h264_mp4toannexb");
}
break;
case AVMEDIA_TYPE_AUDIO:
audio_index = i;
ic->streams[i]->discard = AVDISCARD_NONE;
audio_st = add_output_stream(oc, ic->streams[i]);
if (audio_st->codec->codec_id == CODEC_ID_AAC && !audio_st->codec->extradata_size) {
audio_st->codec->opaque = av_bitstream_filter_init("aac_adtstoasc");
}
break;
default:
ic->streams[i]->discard = AVDISCARD_ALL;
break;
}
}
codec = avcodec_find_decoder(video_st->codec->codec_id);
if (codec == NULL) {
printf("Call avcodec_find_decoder function failed!\n");
return 0;
}
if (avcodec_open2(video_st->codec, codec, NULL) < 0) {
printf("Call avcodec_open function failed !\n");
return 0;
}
if (avio_open(&oc->pb, argv[2], AVIO_FLAG_WRITE) < 0) {
return 0;
}
if (avformat_write_header(oc, &pAVDictionary)) {
printf("Call avformat_write_header function failed.\n");
return 0;
}
int decode_done = 0;
do {
AVPacket packet;
decode_done = av_read_frame(ic, &packet);
if (decode_done < 0) {
break;
}
if (packet.stream_index == video_index && (packet.flags & AV_PKT_FLAG_KEY) && video_st->codec->opaque != NULL) {
AVPacket pkt = packet;
int a = av_bitstream_filter_filter(video_st->codec->opaque, video_st->codec, NULL, &pkt.data, &pkt.size,
packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
if (a == 0) {
memmove(packet.data, pkt.data, pkt.size);
packet.size = pkt.size;
} else if (a > 0) {
packet = pkt;
}
}
else if (packet.stream_index == audio_index && audio_st->codec->opaque != NULL) {
AVPacket pkt = packet;
int a = av_bitstream_filter_filter(audio_st->codec->opaque, audio_st->codec, NULL, &pkt.data, &pkt.size,
packet.data, packet.size, packet.flags & AV_PKT_FLAG_KEY);
if (a == 0) {
memmove(packet.data, pkt.data, pkt.size);
packet.size = pkt.size;
} else if (a > 0) {
packet = pkt;
}
}
nRet = av_interleaved_write_frame(oc, &packet);
if (nRet < 0) {
printf("Call av_interleaved_write_frame function failed\n");
} else if (nRet > 0) {
printf("End of stream requested\n");
av_free_packet(&packet);
break;
}
av_free_packet(&packet);
} while(!decode_done);
av_write_trailer(oc);
av_bitstream_filter_close(video_st->codec->opaque);
av_bitstream_filter_close(audio_st->codec->opaque);
avcodec_close(video_st->codec);
unsigned int k;
for(k = 0; k < oc->nb_streams; k++) {
av_freep(&oc->streams[k]->codec);
av_freep(&oc->streams[k]);
}
av_free(oc);
getchar();
return 0;
}

Hooking NtQueryDirectoryFile can't hide files

I want to hide files (in my program). I decided to use NtQueryDirectoryFile. But the files are not hidden, the code does not work. I don't use a driver, I use user mode. Can anybody help me please?
The code snippet:
typedef NTSTATUS (WINAPI * NTQUERYDIRECTORYFILE) (IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID FileInformation,IN ULONG FileInformationLength,IN MYFILE_INFORMATION_CLASS FileInformationClass,IN BOOLEAN ReturnSingleEntry,IN PUNICODE_STRING FileName OPTIONAL,IN BOOLEAN RestartScan);
NTQUERYDIRECTORYFILE OriginalNtQueryDirectoryFile;
#define STATUS_NO_SUCH_FILE 0xC000000F
NTSTATUS
HookedNtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN MYFILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan)
{
NTSTATUS status = OriginalNtQueryDirectoryFile(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,FileInformation,FileInformationLength,FileInformationClass,ReturnSingleEntry,FileName,RestartScan);
vector<wstring> listDataForHidding;
listDataForHidding.push_back(L"afile.txt");
listDataForHidding.push_back(L"bfile.txt");
listDataForHidding.push_back(L"cfile.txt");
listDataForHidding.push_back(L"dfile.txt");
if (NT_SUCCESS(status))
{
PMYFILE_DIRECTORY_INFORMATION FileDirectoryInfo, LastFileDirectoryInfo;
PMYFILE_FULL_DIR_INFORMATION LastFileFullDirectoryInfo, FileFullDirectoryInfo;
PMYFILE_BOTH_DIR_INFORMATION LastFileBothDirectoryInfo, FileBothDirectoryInfo;
PMYFILE_NAMES_INFORMATION LastFileNamesInfo, FileNamesInfo;
ULONG Offset = 0;
BOOL bNeedHide = FALSE;
switch (FileInformationClass)
{
case FileDirectoryInformation :
FileDirectoryInfo = NULL;
do
{
//FileDirectoryInfo = (PVOID)((ULONG)FileInformation + Offset);
FileDirectoryInfo = (PMYFILE_DIRECTORY_INFORMATION)((ULONG)FileInformation + Offset);
LastFileDirectoryInfo = FileDirectoryInfo;
wstring wstrCurrFileName = FileDirectoryInfo->FileName;
bNeedHide = FALSE;
for(size_t index = 0; index < listDataForHidding.size(); index ++)
{
if(wstrCurrFileName.find(listDataForHidding[index]) != wstring::npos)
{
bNeedHide = TRUE;
break;
}
}
//if (FileDirectoryInfo->FileName[0] == 0x5F00)
if(bNeedHide == TRUE)
{
if (!FileDirectoryInfo->NextEntryOffset)
{
if (LastFileDirectoryInfo) LastFileDirectoryInfo->NextEntryOffset = 0;
else status = STATUS_NO_SUCH_FILE;
return status;
} else
if (LastFileDirectoryInfo) LastFileDirectoryInfo->NextEntryOffset += FileDirectoryInfo->NextEntryOffset;
}
Offset += FileDirectoryInfo->NextEntryOffset;
} while (FileDirectoryInfo->NextEntryOffset);
break;
case FileFullDirectoryInformation :
FileFullDirectoryInfo = NULL;
do
{
LastFileFullDirectoryInfo = FileFullDirectoryInfo;
//FileFullDirectoryInfo = (PVOID)((ULONG)FileInformation + Offset);
FileFullDirectoryInfo = (PMYFILE_FULL_DIR_INFORMATION)((ULONG)FileInformation + Offset);
wstring wstrCurrFileName = FileDirectoryInfo->FileName;
bNeedHide = FALSE;
for(size_t index = 0; index < listDataForHidding.size(); index ++)
{
if(wstrCurrFileName.find(listDataForHidding[index]) != wstring::npos)
{
bNeedHide = TRUE;
break;
}
}
//if (FileFullDirectoryInfo->FileName[0] == 0x5F00)
if(bNeedHide == TRUE)
{
if (!FileFullDirectoryInfo->NextEntryOffset)
{
if (LastFileFullDirectoryInfo) LastFileFullDirectoryInfo->NextEntryOffset = 0;
else status = STATUS_NO_SUCH_FILE;
return status;
} else
if (LastFileFullDirectoryInfo) LastFileFullDirectoryInfo->NextEntryOffset += FileFullDirectoryInfo->NextEntryOffset;
}
Offset += FileFullDirectoryInfo->NextEntryOffset;
} while (FileFullDirectoryInfo->NextEntryOffset);
break;
case FileBothDirectoryInformation :
FileBothDirectoryInfo = NULL;
do
{
LastFileBothDirectoryInfo = FileBothDirectoryInfo;
//FileBothDirectoryInfo = (PVOID)((ULONG)FileInformation + Offset);
FileBothDirectoryInfo = (PMYFILE_BOTH_DIR_INFORMATION)((ULONG)FileInformation + Offset);
wstring wstrCurrFileName = FileDirectoryInfo->FileName;
bNeedHide = FALSE;
for(size_t index = 0; index < listDataForHidding.size(); index ++)
{
if(FileBothDirectoryInfo->FileNameLength > 1 && wstrCurrFileName.find(listDataForHidding[index]) != wstring::npos)
{
bNeedHide = TRUE;
break;
}
}
//if (FileBothDirectoryInfo->FileNameLength > 1 && FileBothDirectoryInfo->FileName[0] == 0x5F00)
if(bNeedHide == TRUE)
{
if (!FileBothDirectoryInfo->NextEntryOffset)
{
if (LastFileBothDirectoryInfo) LastFileBothDirectoryInfo->NextEntryOffset = 0;
else status = STATUS_NO_SUCH_FILE;
return status;
} else
if (LastFileBothDirectoryInfo) LastFileBothDirectoryInfo->NextEntryOffset += FileBothDirectoryInfo->NextEntryOffset;
}
Offset += FileBothDirectoryInfo->NextEntryOffset;
} while (FileBothDirectoryInfo->NextEntryOffset);
break;
case FileNamesInformation :
FileNamesInfo = NULL;
do
{
LastFileNamesInfo = FileNamesInfo;
//FileNamesInfo = (PVOID)((ULONG)FileInformation + Offset);
FileNamesInfo = (PMYFILE_NAMES_INFORMATION)((ULONG)FileInformation + Offset);
wstring wstrCurrFileName = FileDirectoryInfo->FileName;
bNeedHide = FALSE;
for(size_t index = 0; index < listDataForHidding.size(); index ++)
{
if(wstrCurrFileName.find(listDataForHidding[index]) != wstring::npos)
{
bNeedHide = TRUE;
break;
}
}
//if (FileNamesInfo->FileName[0] == 0x5F00)
if(bNeedHide == TRUE)
{
if (!FileNamesInfo->NextEntryOffset)
{
if(LastFileNamesInfo) LastFileNamesInfo->NextEntryOffset = 0;
else status = STATUS_NO_SUCH_FILE;
return status;
} else
if (LastFileNamesInfo) LastFileNamesInfo->NextEntryOffset += FileNamesInfo->NextEntryOffset;
}
Offset += FileNamesInfo->NextEntryOffset;
} while (FileNamesInfo->NextEntryOffset);
break;
}
}
return status;
}

Add an entry to the import table of PE

I'm looking for a command line program to add an entry to the import table of a PE file.
My goal is to add a new imported function from an external DLL to my EXE, and then with ollydbg insert new code using code caves. The new code will use the newly imported function.
Acctualy I've achived my goal, but to add a new entry to the import table I used Stud_PE, which is a GUI application and I want to automate this part of the process.
I'd consider programmatically solutions, but I'm affraid the PE structure is too complex for me to learn and explore in the time frame I have. Moreover if an implementation is already exists, it would be a shame not to use it. :-)
Found what is was looking for.
m-PEFile for c++: http://forum.exetools.com/showpost.php?s=17e7516356489bb9dd17e294e147ef96&p=60183&postcount=3
Also check out pefile for python: http://code.google.com/p/pefile/
And PE/COFF 4J for java: http://pecoff4j.sourceforge.net/
PE/COFF 4J has limited functionality in my opinion, but maybe you'll find it helpful.
Code: PEFile.h
/*******************************************************************************
******************************** Team AT4RE ********************************
********************************************************************************
******************* PLEASE DON'T CHANGE/REMOVE THIS HEADER *******************
********************************************************************************
** **
** Title: PEFile class. **
** Desc: A handy class to manipulate pe files. **
** Author: MohammadHi [ in4matics at hotmail dot com ] **
** WwW: AT4RE [ http://www.at4re.com ] **
** Date: 2008-01-28 **
** **
********************************************************************************
*******************************************************************************/
/*
[ PE File Format ]
---------------------
| DOS Header |
---------------------
| DOS Stub |
---------------------
| PE Header |
---------------------
| Section Table |
---------------------
| Padding |
---------------------
| Section 1 |
---------------------
| Section 2 |
---------------------
| ... |
---------------------
| Section n |
---------------------*/
//==============================================================================
#pragma once
#pragma pack(1)
//==============================================================================
#include <windows.h>
//==============================================================================
#define MAX_SECTION_COUNT 64
#define SECTION_IMPORT "#.import"
#define SECTION_RESERV "#.reserv"
//==============================================================================
struct PE_DOS_HEADER {
WORD Signature;
WORD LastPageBytes;
WORD NumberOfPages;
WORD Relocations;
WORD HeaderSize;
WORD MinMemory;
WORD MaxMemory;
WORD InitialSS;
WORD InitialSP;
WORD Checksum;
WORD InitialIP;
WORD InitialCS;
WORD RelocTableOffset;
WORD Overlay;
WORD Reserved1[4];
WORD OemId;
WORD OemInfo;
WORD Reserved2[10];
LONG PEHeaderOffset;
};
struct PE_DOS_STUB {
char* RawData;
DWORD Size;
};
struct PE_SECTION_DATA {
DWORD Offset;
char* RawData;
DWORD Size;
};
struct PE_IMPORT_FUNCTION {
char* FunctionName;
int FunctionId;
PE_IMPORT_FUNCTION* Next;
};
struct PE_IMPORT_DLL {
char* DllName;
PE_IMPORT_FUNCTION* Functions;
PE_IMPORT_DLL* Next;
};
//==============================================================================
typedef IMAGE_NT_HEADERS PE_NT_HEADERS;
typedef IMAGE_SECTION_HEADER PE_SECTION_HEADER;
//==============================================================================
class PEFile {
public:
PE_DOS_HEADER dosHeader;
PE_DOS_STUB dosStub;
PE_NT_HEADERS peHeaders;
PE_SECTION_HEADER sectionTable[MAX_SECTION_COUNT];
PE_SECTION_DATA reservedData;
PE_SECTION_DATA sections[MAX_SECTION_COUNT];
PE_IMPORT_DLL importTable;
PE_IMPORT_DLL newImports;
PEFile();
PEFile(char* filePath);
~PEFile();
bool loadFromFile(char* filePath);
bool loadFromMemory(char* memoryAddress);
bool saveToFile(char* filePath);
int addSection(char* name, DWORD size, bool isExecutable);
void addImport(char* dllName, char** functions, int functionCount);
void commit();
private:
char* peMemory;
void init();
bool readFileData(char* filePath);
bool checkValidity();
bool readHeaders();
bool readBody();
bool readImportTable();
bool writePadding(HANDLE fileHandle, long paddingSize);
void unloadFile();
void buildImportTable();
char* buildNewImports(DWORD baseRVA);
DWORD calcNewImportsSize(DWORD &sizeDlls, DWORD &sizeFunctions, DWORD &sizeStrings);
DWORD alignNumber(DWORD number, DWORD alignment);
DWORD rvaToOffset(DWORD rva);
DWORD offsetToRVA(DWORD offset);
void fixReservedData();
void fixHeaders();
void fixSectionTable();
};
//==============================================================================
Code: PEFile.cpp
/*******************************************************************************
******************************** Team AT4RE ********************************
********************************************************************************
******************* PLEASE DON'T CHANGE/REMOVE THIS HEADER *******************
********************************************************************************
** **
** Title: PEFile class. **
** Desc: A handy class to manipulate pe files. **
** Author: MohammadHi [ in4matics at hotmail dot com ] **
** WwW: AT4RE [ http://www.at4re.com ] **
** Date: 2008-01-28 **
** **
********************************************************************************
*******************************************************************************/
#include "PEFile.h"
#include <math.h>
//==============================================================================
#define DEBUG_ENABLED true;
#ifdef DEBUG_ENABLED
#define echo(x) MessageBox(0, x, "DEBUG", MB_ICONERROR);
#define echo2(x, y) { char v[256]; strcpy_s(v, 256, x); strcat_s(v, 256, y); echo(v); }
#define echo3(x, y, z) { char w[256]; strcpy_s(w, 256, x); strcat_s(w, 256, y); echo2(w, z); }
#else
#define echo(x) ;
#define echo2(x, y) ;
#define echo3(x, y, z) ;
#endif
//==============================================================================
PEFile::PEFile() {
init();
}
//==============================================================================
PEFile::PEFile(char* filePath) {
init();
loadFromFile(filePath);
}
//==============================================================================
PEFile::~PEFile() {
unloadFile();
}
//==============================================================================
void PEFile::init() {
peMemory = NULL;
ZeroMemory(&newImports, sizeof(PE_IMPORT_DLL));
}
//==============================================================================
bool PEFile::readFileData(char* filePath) {
// open the file for read
HANDLE fileHandle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) {
echo3("Couldn't open file : [", filePath, "]");
return false;
}
// get the file size
DWORD fileSize = GetFileSize(fileHandle, 0);
if (fileSize == 0) {
CloseHandle(fileHandle);
echo3("File size is ZeR0! : [", filePath, "]");
return false;
}
// allocate memory to read the pe file (note that we used VirtualAlloc not GlobalAlloc!)
peMemory = (char*)VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (peMemory == NULL) {
CloseHandle(fileHandle);
echo("Couldn't allocate memory!");
return false;
}
DWORD bytesRead;
// read whole file data
if (!ReadFile(fileHandle, peMemory, fileSize, &bytesRead, NULL) || bytesRead != fileSize) {
CloseHandle(fileHandle);
echo3("Couldn't read file! : [", filePath, "]");
return false;
}
// close the file
CloseHandle(fileHandle);
return true;
}
//==============================================================================
bool PEFile::checkValidity() {
// 'dosHeader.Signature' must be "MZ" && 'peHeaders.Signature' must be "PE\0\0"
if (dosHeader.Signature != IMAGE_DOS_SIGNATURE || peHeaders.Signature != IMAGE_NT_SIGNATURE) {
unloadFile();
echo("Invalid PE file!");
return false;
}
if (peHeaders.FileHeader.NumberOfSections > MAX_SECTION_COUNT) {
unloadFile();
echo("Number of sections > MAX_SECTION_COUNT !");
return false;
}
return true;
}
//==============================================================================
bool PEFile::readHeaders() {
// read dos/pe headers
CopyMemory(&dosHeader, peMemory, sizeof(PE_DOS_HEADER));
dosStub.RawData = peMemory + sizeof(PE_DOS_HEADER);
dosStub.Size = dosHeader.PEHeaderOffset - sizeof(PE_DOS_HEADER);
CopyMemory(&peHeaders, peMemory + dosHeader.PEHeaderOffset, sizeof(PE_NT_HEADERS));
// check validity of the file to ensure that we loaded a "PE File" not another thing!
if (!checkValidity()) {
return false;
}
// read section table
ZeroMemory(sectionTable, sizeof(sectionTable));
CopyMemory(sectionTable, peMemory + dosHeader.PEHeaderOffset + sizeof(PE_NT_HEADERS),
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER));
return true;
}
//==============================================================================
bool PEFile::readBody() {
// read reserved data
DWORD reservedDataOffset = dosHeader.PEHeaderOffset + sizeof(PE_NT_HEADERS) +
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER);
reservedData.Offset = reservedDataOffset;
reservedData.RawData = peMemory + reservedDataOffset;
/*reservedData.Size = peHeaders.OptionalHeader.SizeOfHeaders - reservedDataOffset;*/
if (sectionTable[0].PointerToRawData > 0) {
reservedData.Size = sectionTable[0].PointerToRawData - reservedDataOffset;
} else {
reservedData.Size = sectionTable[0].VirtualAddress - reservedDataOffset;
}
// read sections
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
sections[i].Offset = sectionTable[i].PointerToRawData;
sections[i].RawData = peMemory + sectionTable[i].PointerToRawData;
sections[i].Size = sectionTable[i].SizeOfRawData;
}
return true;
}
//==============================================================================
bool PEFile::readImportTable() {
DWORD tableRVA = peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD tableOffset = rvaToOffset(tableRVA);
if (tableOffset == 0) {
return false;
}
ZeroMemory(&importTable, sizeof(PE_IMPORT_DLL));
IMAGE_IMPORT_DESCRIPTOR* importDesc = (IMAGE_IMPORT_DESCRIPTOR*)(peMemory + tableOffset);
IMAGE_THUNK_DATA* importThunk;
PE_IMPORT_DLL* importDll = &this->importTable;
PE_IMPORT_FUNCTION* importFunction;
while (true) {
importDll->DllName = (char*)(peMemory + rvaToOffset(importDesc->Name));
if (importDesc->OriginalFirstThunk > 0) {
importThunk = (IMAGE_THUNK_DATA*)(peMemory + rvaToOffset(importDesc->OriginalFirstThunk));
} else {
importThunk = (IMAGE_THUNK_DATA*)(peMemory + rvaToOffset(importDesc->FirstThunk));
}
importDll->Functions = new PE_IMPORT_FUNCTION();
ZeroMemory(importDll->Functions, sizeof(PE_IMPORT_FUNCTION));
importFunction = importDll->Functions;
while (true) {
if ((importThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32) == IMAGE_ORDINAL_FLAG32) {
importFunction->FunctionId = IMAGE_ORDINAL32(importThunk->u1.Ordinal);
} else {
DWORD nameOffset = rvaToOffset(importThunk->u1.AddressOfData);
importFunction->FunctionName = (char*)(peMemory + nameOffset + 2);
}
importThunk = (IMAGE_THUNK_DATA*)((char*)importThunk + sizeof(IMAGE_THUNK_DATA));
if (importThunk->u1.AddressOfData == 0) {
break;
}
importFunction->Next = new PE_IMPORT_FUNCTION();
ZeroMemory(importFunction->Next, sizeof(PE_IMPORT_FUNCTION));
importFunction = importFunction->Next;
}
importDesc = (IMAGE_IMPORT_DESCRIPTOR*)((char*)importDesc + sizeof(IMAGE_IMPORT_DESCRIPTOR));
if (importDesc->Name == 0) {
break;
}
importDll->Next = new PE_IMPORT_DLL();
ZeroMemory(importDll->Next, sizeof(PE_IMPORT_DLL));
importDll = importDll->Next;
}
return true;
}
//==============================================================================
bool PEFile::loadFromFile(char* filePath) {
unloadFile();
return readFileData(filePath) &&
readHeaders() &&
readBody() &&
readImportTable();
}
//==============================================================================
bool PEFile::loadFromMemory(char* memoryAddress) {
unloadFile();
peMemory = memoryAddress;
return readHeaders()/* &&
readBody() &&
readImportTable()*/;
}
//==============================================================================
bool PEFile::saveToFile(char* filePath) {
commit();
buildImportTable();
// create the output file
HANDLE fileHandle = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) {
echo("Couldn't create file");
return false;
}
DWORD bytesWritten;
WriteFile(fileHandle, &dosHeader, sizeof(PE_DOS_HEADER), &bytesWritten, NULL);
WriteFile(fileHandle, dosStub.RawData, dosStub.Size, &bytesWritten, NULL);
writePadding(fileHandle, dosHeader.PEHeaderOffset - sizeof(PE_DOS_HEADER) - dosStub.Size);
WriteFile(fileHandle, &peHeaders, sizeof(PE_NT_HEADERS), &bytesWritten, NULL);
WriteFile(fileHandle, &sectionTable, peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER), &bytesWritten, NULL);
WriteFile(fileHandle, reservedData.RawData, reservedData.Size, &bytesWritten, NULL);
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
writePadding(fileHandle, sectionTable[i].PointerToRawData - GetFileSize(fileHandle, NULL));
WriteFile(fileHandle, sections[i].RawData, sections[i].Size, &bytesWritten, NULL);
}
CloseHandle(fileHandle);
return true;
}
//==============================================================================
bool PEFile::writePadding(HANDLE fileHandle, long paddingSize) {
if (paddingSize <= 0)
return false;
DWORD bytesWritten;
char* padding = new char[paddingSize];
memset(padding, 0, paddingSize);
WriteFile(fileHandle, padding, paddingSize, &bytesWritten, NULL);
delete padding;
return (bytesWritten == paddingSize);
}
//==============================================================================
void PEFile::unloadFile() {
if (peMemory != NULL) {
VirtualFree(peMemory, 0, MEM_RELEASE);
peMemory = NULL;
}
}
//==============================================================================
void PEFile::buildImportTable() {
DWORD sizeDlls = 0;
DWORD sizeFunctions = 0;
DWORD sizeStrings = 0;
DWORD newImportsSize = calcNewImportsSize(sizeDlls, sizeFunctions, sizeStrings);
// we'll move the old dll list to the new import table, so we'll calc its size
DWORD oldImportDllsSize = 0;
PE_IMPORT_DLL* importDll = &this->importTable;
while (importDll != NULL) {
oldImportDllsSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
importDll = importDll->Next;
}
// add a new section to handle the new import table
int index = addSection(SECTION_IMPORT, oldImportDllsSize + newImportsSize, false);
// copy old import dll list
DWORD oldImportTableRVA = peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD oldImportTableOffset = rvaToOffset(oldImportTableRVA);
CopyMemory(sections[index].RawData, peMemory + oldImportTableOffset, oldImportDllsSize);
// copy new imports
char* newImportsData = buildNewImports(sectionTable[index].VirtualAddress + oldImportDllsSize);
CopyMemory(sections[index].RawData + oldImportDllsSize, newImportsData, newImportsSize);
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = sectionTable[index].VirtualAddress;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sectionTable[index].SizeOfRawData;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
//==============================================================================
char* PEFile::buildNewImports(DWORD baseRVA) {
commit();
IMAGE_IMPORT_DESCRIPTOR importDesc;
IMAGE_THUNK_DATA importThunk;
PE_IMPORT_DLL* importDll;
PE_IMPORT_FUNCTION* importFunction;
DWORD sizeDlls = 0;
DWORD sizeFunctions = 0;
DWORD sizeStrings = 0;
DWORD newImportsSize = calcNewImportsSize(sizeDlls, sizeFunctions, sizeStrings);
DWORD offsetDlls = 0;
DWORD offsetFunctions = sizeDlls;
DWORD offsetStrings = sizeDlls + 2 * sizeFunctions;
char* buffer = new char[newImportsSize];
ZeroMemory(buffer, newImportsSize);
importDll = &newImports;
while (importDll != NULL) {
ZeroMemory(&importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
importDesc.OriginalFirstThunk = baseRVA + offsetFunctions;
importDesc.FirstThunk = baseRVA + offsetFunctions + sizeFunctions;
importDesc.Name = baseRVA + offsetStrings;
CopyMemory(buffer + offsetStrings, importDll->DllName, strlen(importDll->DllName));
offsetStrings += alignNumber((DWORD)strlen(importDll->DllName) + 1, 2);
CopyMemory(buffer + offsetDlls, &importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
offsetDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR);
importFunction = importDll->Functions;
while (importFunction != NULL) {
ZeroMemory(&importThunk, sizeof(IMAGE_THUNK_DATA));
if (importFunction->FunctionId != 0) {
importThunk.u1.Ordinal = importFunction->FunctionId | IMAGE_ORDINAL_FLAG32;
} else {
importThunk.u1.AddressOfData = baseRVA + offsetStrings;
CopyMemory(buffer + offsetStrings + 2, importFunction->FunctionName, strlen(importFunction->FunctionName));
offsetStrings += 2 + alignNumber((DWORD)strlen(importFunction->FunctionName) + 1, 2);
}
CopyMemory(buffer + offsetFunctions, &importThunk, sizeof(IMAGE_THUNK_DATA));
CopyMemory(buffer + offsetFunctions + sizeFunctions, &importThunk, sizeof(IMAGE_THUNK_DATA));
offsetFunctions += sizeof(IMAGE_THUNK_DATA);
importFunction = importFunction->Next;
}
offsetFunctions += sizeof(IMAGE_THUNK_DATA);
importDll = importDll->Next;
}
return buffer;
}
//==============================================================================
DWORD PEFile::calcNewImportsSize(DWORD &sizeDlls, DWORD &sizeFunctions, DWORD &sizeStrings) {
PE_IMPORT_DLL* importDll = &this->newImports;
PE_IMPORT_FUNCTION* importFunction;
// calc added imports size
while (importDll != NULL) {
sizeDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR);
sizeStrings += alignNumber((DWORD)strlen(importDll->DllName) + 1, 2);
importFunction = importDll->Functions;
while (importFunction != NULL) {
sizeFunctions += sizeof(IMAGE_THUNK_DATA);
if (importFunction->FunctionId == 0) {
sizeStrings += 2 + alignNumber((DWORD)strlen(importFunction->FunctionName) + 1, 2);
}
importFunction = importFunction->Next;
}
sizeFunctions += sizeof(IMAGE_THUNK_DATA); // for the terminator thunk data
importDll = importDll->Next;
}
sizeDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR); // for the terminator import descriptor
return sizeDlls + 2 * sizeFunctions + sizeStrings;
}
//==============================================================================
int PEFile::addSection(char* name, DWORD size, bool isExecutable) {
if (peHeaders.FileHeader.NumberOfSections == MAX_SECTION_COUNT) {
return -1;
}
PE_SECTION_DATA &newSection = sections[peHeaders.FileHeader.NumberOfSections];
PE_SECTION_HEADER &newSectionHeader = sectionTable[peHeaders.FileHeader.NumberOfSections];
PE_SECTION_HEADER &lastSectionHeader = sectionTable[peHeaders.FileHeader.NumberOfSections - 1];
DWORD sectionSize = alignNumber(size, peHeaders.OptionalHeader.FileAlignment);
DWORD virtualSize = alignNumber(sectionSize, peHeaders.OptionalHeader.SectionAlignment);
DWORD sectionOffset = alignNumber(lastSectionHeader.PointerToRawData + lastSectionHeader.SizeOfRawData, peHeaders.OptionalHeader.FileAlignment);
DWORD virtualOffset = alignNumber(lastSectionHeader.VirtualAddress + lastSectionHeader.Misc.VirtualSize, peHeaders.OptionalHeader.SectionAlignment);
ZeroMemory(&newSectionHeader, sizeof(IMAGE_SECTION_HEADER));
CopyMemory(newSectionHeader.Name, name, (strlen(name) > 8 ? 8 : strlen(name)));
newSectionHeader.PointerToRawData = sectionOffset;
newSectionHeader.VirtualAddress = virtualOffset;
newSectionHeader.SizeOfRawData = sectionSize;
newSectionHeader.Misc.VirtualSize = virtualSize;
newSectionHeader.Characteristics = //0xC0000040;
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
if (isExecutable) {
newSectionHeader.Characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
}
newSection.RawData = (char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sectionSize);
newSection.Size = sectionSize;
peHeaders.FileHeader.NumberOfSections++;
if (reservedData.Size > 0) {
reservedData.Size -= sizeof(IMAGE_SECTION_HEADER);
}
// return new section index
return peHeaders.FileHeader.NumberOfSections - 1;
}
//==============================================================================
void PEFile::addImport(char* dllName, char** functions, int functionCount) {
PE_IMPORT_DLL* importDll = &this->newImports;
PE_IMPORT_FUNCTION* importFunction;
if (newImports.DllName != NULL) {
while (importDll->Next != NULL) {
importDll = importDll->Next;
}
importDll->Next = new PE_IMPORT_DLL();
importDll = importDll->Next;
}
importDll->DllName = dllName;
importDll->Functions = new PE_IMPORT_FUNCTION();
importDll->Next = NULL;
importFunction = importDll->Functions;
importFunction->FunctionName = functions[0];
for (int i = 1; i < functionCount; i++) {
importFunction->Next = new PE_IMPORT_FUNCTION();
importFunction = importFunction->Next;
importFunction->FunctionName = functions[i];
}
importFunction->Next = NULL;
}
//==============================================================================
DWORD PEFile::alignNumber(DWORD number, DWORD alignment) {
return (DWORD)(ceil(number / (alignment + 0.0)) * alignment);
}
//==============================================================================
DWORD PEFile::rvaToOffset(DWORD rva) {
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
if (rva >= sectionTable[i].VirtualAddress &&
rva < sectionTable[i].VirtualAddress + sectionTable[i].Misc.VirtualSize) {
return sectionTable[i].PointerToRawData + (rva - sectionTable[i].VirtualAddress);
}
}
return 0;
}
//==============================================================================
DWORD PEFile::offsetToRVA(DWORD offset) {
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
if (offset >= sectionTable[i].PointerToRawData &&
offset < sectionTable[i].PointerToRawData + sectionTable[i].SizeOfRawData) {
return sectionTable[i].VirtualAddress + (offset - sectionTable[i].PointerToRawData);
}
}
return 0;
}
//==============================================================================
void PEFile::commit() {
fixReservedData();
fixHeaders();
fixSectionTable();
}
//==============================================================================
void PEFile::fixReservedData() {
DWORD dirIndex = 0;
for (dirIndex = 0; dirIndex < peHeaders.OptionalHeader.NumberOfRvaAndSizes; dirIndex++) {
if (peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress > 0 &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress >= reservedData.Offset &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress < reservedData.Size) {
break;
}
}
if (dirIndex == peHeaders.OptionalHeader.NumberOfRvaAndSizes) {
return;
}
int sectionIndex = addSection(SECTION_RESERV, reservedData.Size, false);
CopyMemory(sections[sectionIndex].RawData, reservedData.RawData, reservedData.Size);
for (dirIndex = 0; dirIndex < peHeaders.OptionalHeader.NumberOfRvaAndSizes; dirIndex++) {
if (peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress > 0 &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress >= reservedData.Offset &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress < reservedData.Size) {
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress +=
sectionTable[sectionIndex].VirtualAddress - reservedData.Offset;
}
}
reservedData.Size = 0;
}
//==============================================================================
void PEFile::fixHeaders() {
peHeaders.OptionalHeader.SizeOfHeaders = alignNumber(dosHeader.PEHeaderOffset + peHeaders.FileHeader.SizeOfOptionalHeader +
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER), peHeaders.OptionalHeader.FileAlignment);
DWORD imageSize = peHeaders.OptionalHeader.SizeOfHeaders;
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
imageSize += alignNumber(sectionTable[i].Misc.VirtualSize, peHeaders.OptionalHeader.SectionAlignment);
}
peHeaders.OptionalHeader.SizeOfImage = alignNumber(imageSize, peHeaders.OptionalHeader.SectionAlignment);
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
}
//==============================================================================
void PEFile::fixSectionTable() {
DWORD offset = peHeaders.OptionalHeader.SizeOfHeaders;
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
sectionTable[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
offset = alignNumber(offset, peHeaders.OptionalHeader.FileAlignment);
sectionTable[i].PointerToRawData = offset;
//sectionTable[i].SizeOfRawData = alignNumber(offset + sectionTable[i].Misc.VirtualSize, peHeaders.OptionalHeader.FileAlignment);
offset += sectionTable[i].SizeOfRawData;
}
}
//==============================================================================
#include "PEFile.h"
int main(int argc, char* argv[]) {
// Open the input file
PEFile pe("1.exe");
// Add "MessageBoxA" & "ShowWindow" functions to the import table
char* functions[] = { "MessageBoxA", "ShowWindow" };
pe.addImport("user32.dll", functions, 2);
// Add a new section named ".at4re" with size "0x1000" byte
pe.addSection(".at4re", 0x1000, false);
// Save the modified file
pe.saveToFile("1+.exe");
}
You can use the PeNet library to add a new import with just one line of code. For an example see here: Adding Imports
var peFile = new PeFile("myapp.exe");
peFile.AddImport("gdi32.dll", "StartPage");
I was looking for such program myself. I failed too.
But it is very easily done by hand.
If you need to automate it then you can make your own program.
Go to http://www.unknowncheats.me/forum/ or http://www.rohitab.com
People there will be able to help you write your own program.

Resources