0

im writing a c++ program that involves ffmpeg being called from a c++ program. a couple of days ago i got it working using std::system

std::system("ffmpeg -threads auto -y -r 1.74659 -i /mnt/ev_ramdsk/1/%05d-capture.jpg -px_fmt yuv420p -preset ultrafast -r 10 /mnt/ev_ramdsk/1/video.mp4");

but this only worked once now this produces .mp4 videos of 8MB or so that cannot be played anywhere.. so because of a suggestion in a previous question i moved to execve.

Here is my code

child_pid = fork();
        if(child_pid < 0){
            syslog(LOG_ERR, "ERROR: ffmpeg forking failed");
            return false;
        }
        else if(child_pid > 0){
            syslog(LOG_DEBUG, "DEBUG: forking succeeded, pid: %d", child_pid);
        }
        else if(child_pid == 0){
            char *newargv[16];
            for(int i=0; i < 15; i++) newargv[i] = (char *)malloc(sizeof(char) * 60); //allocate the array in memory
            strcpy(newargv[0], "/usr/bin/ffmpeg");
            strcpy(newargv[1], "-threads");
            strcpy(newargv[2], "auto");
            strcpy(newargv[3], "-y");
            strcpy(newargv[4], "-framerate");
            tempSS << fps;
            strcpy(newargv[5], tempSS.str().c_str());
            tempSS.str(std::string());
            strcpy(newargv[6], "-i");
            strcpy(newargv[7], std::string(conf->dir_ram + dest + "%05d-capture.jpg").c_str());
            strcpy(newargv[8], "-pix_fmt");
            strcpy(newargv[9], "yuv420p");
            strcpy(newargv[10], "-preset");
            strcpy(newargv[11], "ultrafast");
            strcpy(newargv[12], "-r");
            strcpy(newargv[13], "25");
            strcpy(newargv[14], std::string(conf->dir_ram + dest + "video.mp4").c_str());
            newargv[15] = NULL;

            for(int i=0; i < 15; i++){
                tempSS << "newargv[" << i << "] = \"" << newargv[i] << "\", ";
            }
            syslog(LOG_DEBUG, "DEBUG:newargv: %s", tempSS.str().c_str());
            tempSS.str(std::string());

            char *newenviron[] = { NULL };

            if(execve(newargv[0], newargv, newenviron) == -1){
                syslog(LOG_ERR, "ERROR: execve returned -1");
                exit(EXIT_SUCCESS);
            }
        }

        wpid = wait(&status);
        syslog(LOG_DEBUG, "DEBUG: ffmpeg child terminated, pid: %d, status: %d", wpid, status);

the output of syslog is:

May 28 00:25:03 SERVER dt_ev_maker[10471]: DEBUG: forking succeeded, pid: 10658
May 28 00:25:03 SERVER dt_ev_maker[10658]: DEBUG:newargv: 
newargv[0] = "/usr/bin/ffmpeg", 
newargv[1] = "-threads", 
newargv[2] = "auto", 
newargv[3] = "-y", 
newargv[4] = "-framerate", 
newargv[5] = "1.45097", 
newargv[6] = "-i", 
newargv[7] = "/mnt/ev_ramdsk/1/%05d-capture.jpg", 
newargv[8] = "-pix_fmt", 
newargv[9] = "yuv420p", 
newargv[10] = "-preset", 
newargv[11] = "ultrafast", 
newargv[12] = "-r", 
newargv[13] = "25", 
newargv[14] = "/mnt/ev_ramdsk/1/video.mp4",
May 28 00:25:03 SERVER dt_ev_maker[10471]: DEBUG: ffmpeg child terminated, pid: 10658, status: 256

in this case the video has about 90B size and is also corrupted.

NOTE: if i run the same command from the command line the video can be played normally.

what am i doing wrong?

Thanks in advance!

EDIT

Thanks to ouroborus (changes submitted above) i got it to make 18MB videos, but i cant play them.

Arheisel
  • 186
  • 11
  • yes, the files exist and the program makes sure they do before executing – Arheisel May 28 '16 at 03:45
  • Why is your frame rate set to **1.45097**? Are you making a slide show? – VC.One May 30 '16 at 04:12
  • No, but the input is a recording from a webcam, and it happens to be at that rate – Arheisel May 30 '16 at 10:51
  • Well 1.45097 FPS is just ridiculous, might as well be 1 FPS. Is it some kind of security CCTV camera? Anyways does the webcam software produce any video by itself? Are those videos playable by other external software & those correctly report 1.45097 as the FPS? It might be the answer as to why your videos are not payable... make like a 30 FPS frame rate video where each JPEG image has a duration of 1 second. Does that video work? – VC.One May 30 '16 at 19:21
  • Tested it, still not working – Arheisel May 31 '16 at 02:14
  • I think you better provide a link to a test output file. PS: I had typed an answer yesterday but deleted it to ask about your frame rate instead... Anyways the suggestion was to make a h264 video instead (and later mux that into MP4). Also I myself had specify two output files so that might work for you... example is `[14] = videoTemp.h264 and [15] = Video.h264`. I'll explain the why later (probably an MPEG thing)... – VC.One May 31 '16 at 02:29
  • 1
    okay, about 20 minutes ago the program started to randomly produce good videos (since the last build). i was messing around with file descriptors, so i didnt change the execve at all. this is the second time it happens so ill backup the script and executable file and try to figure this out – Arheisel May 31 '16 at 02:39
  • Glad it's working, for me the randomly good videos came only after two outputs instead of one... Also it might be worth adding a `-c:v libx264` before the `ultrafast preset` y'know just incase ... `strcpy(newargv[n1], "-c:v"); strcpy(newargv[n2], "libx264");`. – VC.One May 31 '16 at 03:54
  • You dont understand, i didnt change anyting at all, i was working with an error check sowhere else in the script (after the conversion) when it began to work (for the second time). So ill add the libx264 and see how it behaves because the last time it was working and just like that stopped and,now, just like that it works – Arheisel May 31 '16 at 03:55
  • I understand perfectly. I just casually mentioned how it worked out for me. I also suggested you specify a codec cos nothing is guaranteed (I had assumptions too when I started with this ****, I learnt it's best to be specific with output options). Anyway keep not changing anything since that's working... – VC.One May 31 '16 at 04:01
  • Ok, ill wrap everything up and post the "answer" as the code that finally decided to work. Thnaks everyone! – Arheisel May 31 '16 at 04:03

2 Answers2

1

It seems that execve() needs it's arrays to have a last element that is NULL. Extend your newargv array by one and set the last element to NULL before passing it into execve().

Ref: Using execve for the first time

Ouroborus
  • 16,237
  • 4
  • 39
  • 62
  • this solved the problem of the 90B videos, now it outputs 16MB unplayable videos, big improvement but not quite there, thanks! – Arheisel May 28 '16 at 04:03
  • You said you're also having problems with the original `system()` version. I think your code is otherwise fine so I'd suggest seeing if you can get the ffmpeg command itself to run properly from the console. – Ouroborus May 28 '16 at 04:05
  • strangley, when i run the same commands from the comand line it works perfectly! maybe the problem is ffmpeg itself – Arheisel May 28 '16 at 04:11
  • ffmpeg produces quite a bit in the way of logs. Perhaps there's something in there. ([This](http://www.ozzu.com/programming-forum/execve-with-redirection-t59743.html) is in C and for `execpl` but the principle is the same.) – Ouroborus May 28 '16 at 04:17
  • tried it and gives me an empty file, im still trying to figure out wht it didint work, maybe ill have better luck with the system call – Arheisel May 31 '16 at 02:35
1

So, the code that finally worked was:

pid_t wpid, child_pid;
            int status;
            int fd = open(std::string(conf->dir_ram + "ffmpeg.txt").c_str(), O_CREAT | O_WRONLY, 0777);
            if(fd < 0){
                syslog(LOG_ERR, "ERROR: open returned -1");
                return false;
            }

            child_pid = fork();
            if(child_pid < 0){
                syslog(LOG_ERR, "ERROR: ffmpeg forking failed");
                return false;
            }
            else if(child_pid > 0){
                syslog(LOG_DEBUG, "DEBUG: forking succeeded, pid: %d", child_pid);
            }
            else if(child_pid == 0){

                if( close(1) < 0 ){
                    syslog(LOG_ERR, "ERROR: close returned -1");
                    return false;
                }
                if( dup2(fd, 1) < 0 ){
                    syslog(LOG_ERR, "ERROR: dup2 returned -1");
                    return false;
                }

                char *newargv[18];
                for(int i=0; i < 17; i++) newargv[i] = (char *)malloc(sizeof(char) * 60); //allocate the array in memory
                strcpy(newargv[0], conf->ffmpeg_path.c_str());
                strcpy(newargv[1], "-threads");
                strcpy(newargv[2], "auto");
                strcpy(newargv[3], "-y");
                strcpy(newargv[4], "-r");
                tempSS << fps;
                strcpy(newargv[5], tempSS.str().c_str());
                tempSS.str(std::string());
                strcpy(newargv[6], "-i");
                strcpy(newargv[7], std::string(conf->dir_ram + dest + "%05d-capture.jpg").c_str());
                strcpy(newargv[8], "-pix_fmt");
                strcpy(newargv[9], "yuv420p");
                strcpy(newargv[10], "-c:v");
                strcpy(newargv[11], "libx264");
                strcpy(newargv[12], "-preset");
                strcpy(newargv[13], "ultrafast");
                strcpy(newargv[14], "-r");
                strcpy(newargv[15], conf->ffmpeg_rate.c_str());
                strcpy(newargv[16], std::string(conf->dir_ram + dest + "video.mp4").c_str());
                newargv[17] = NULL;

                char *newenviron[] = { NULL };

                if(execve(newargv[0], newargv, newenviron) == -1){
                    syslog(LOG_ERR, "ERROR: execve returned -1");
                    exit(EXIT_SUCCESS);
                }
            }

            wpid = wait(&status);

if i comment the whole open() and dup2() part the videos get corrupted. i have no idea why, but without that it doesnt work.

Arheisel
  • 186
  • 11