Page 2 of 5

Re: Recording and streaming emu frames

Posted: Mon Dec 22, 2014 4:39 pm
by tepples
Essentially you have to open a pipe into FFmpeg or avconv that accepts raw RGB and produces AVI in some compressed format. The command line for such a pipe might look like this example that Wrecking Ball Boy and my Pygame remake of FHBG use to encode on the fly:

Code: Select all

avconv -f rawvideo -pix_fmt rgb24 -s "256x208" -r 30 -an -i - -c:v png tmp.avi
I'll break this down for you:
  • avconv: This is a fork of FFmpeg that happens to be the default in Debian.
  • -f rawvideo -pix_fmt rgb24: Input shall be a string of 3-byte RGB pixels, left to right, in rows to bottom.
  • -s "256x208": Each row is 256 pixels (768 bytes) long, and there are 208 rows (159744 bytes) in each picture.
  • -r 30: The video shall be played back at 30 pictures per second.
  • -i -: The input is standard input from a pipe, not a file.
  • -c:v png: The output shall use the FFmpeg "Motion PNG" codec, which is a sequence of PNG images in the same way that Motion JPEG is a sequence of JPEG images. If you have compiled FFmpeg with support for Huffyuv or Lagarith, you can use that instead of PNG.
  • tmp.avi: This is where the video file shall be written.

Re: Recording and streaming emu frames

Posted: Tue Dec 23, 2014 7:15 am
by Anes
Sorry the noob questions:

- do i have to call externaly "avconv"?
- How to add sound?

Re: Recording and streaming emu frames

Posted: Tue Dec 23, 2014 1:56 pm
by koitsu
I think what's been overlooked is Anes is asking how to do all of this within software (e.g. C, some library API, etc.) and not "how do I use an external program to do this". I thought that was apparent from his initial post ("... comming from emulation playing ... realtime encode to mpeg2 or another format ...").

I don't think spawning some external executable is really the way to go for this type of thing.

Nestopia has native code to do all of this already, so that may be a good place to start looking source-code-wise.

Re: Recording and streaming emu frames

Posted: Tue Dec 23, 2014 2:35 pm
by Anes
koitsu wrote:I think what's been overlooked is Anes is asking how to do all of this within software (e.g. C, some library API, etc.) and not "how do I use an external program to do this". I thought that was apparent from his initial post ("... comming from emulation playing ... realtime encode to mpeg2 or another format ...").
Thats right... i want to make in the software...
for me Windows Video 1 is ok for movies. What i cannot acchive is writing mp3 data to the avi using vfw.
The video part is ok i can record, but the sound part isn't.
Im using lame to encode in realtime sound but i don't know how to use vfw for writing the mp3 data.
I suppouse that using AVIFileCreateStream() in conjuntion with AVIMakeCompressedStream() could help me, but i don't know how to do it.

Re: Recording and streaming emu frames

Posted: Tue Dec 23, 2014 6:39 pm
by rockcarry
I have already implemented the video recording of nes emulator. I make a project named ffencoder which code is based on ffmpeg for recording nes emulator audio and video into mp4 file encoding by aac and h264.

You can see my project ffnes and ffencoder on github for your reference:
https://github.com/rockcarry/ffnes
https://github.com/rockcarry/ffencoder

ffencoder simply wraps around ffmpeg encoding and muxing functions, and it's easy to use.

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 9:57 am
by Anes
I know it's an off topic but i need help.

well i installed ubuntu and successfully comiled the ffencoder.dll.

I made the following to make a .lib file from the .dll:

i created a .def file with the four function names and EXPORT in the top of the file.
i ran msvc lib tool to make the .lib and it made it well.
I included the path to the .lib in msvc and put the ffencoder.lib to link to.
No luck, the compiler throw me "unresolved external symbol xxx" whree "xxx" are the functions in the .dll.

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 6:54 pm
by Boolean
I think it's good to compile the ffencoder source files to various versions.
For example, Linux, Win32(Visual C++) and Win32(MinGW32).
Like this http://libsdl.org/download-1.2.php

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 7:55 pm
by Anes
Reading msdn doc i could meke it work the ffencoder.dll

The thing is that ffencoder_init() throw me and exception. I don't know if anybody apart of rockcarry uses it, but im doing the following:

Code: Select all

FFENCODER_PARAMS ffpar;
void * ffhandle;

    ffpar.filename = szMovieDir;   //this is the path to the .mp4 movie
    // video params
    ffpar.video_bitrate = 2000;
    ffpar.video_width = 256;
    ffpar.video_height = 240;
    ffpar.frame_rate = 60;
    ffpar.pixel_fmt = 32;
    ffpar.scale_flags = 0;    //i don't know what this member is for
    ffpar.start_vpts = 0;     //i don't know what this member is for
    // audio params
    ffpar.audio_bitrate = 128;
    ffpar.sample_rate = 44100;
    ffpar.channel_layout = 4;    //taken by looking in ffmpeg doc, it is "mono" i think
    ffpar.start_apts = 0;    //i don't know what this member is for
    ffpar.enable_log = 0;   //i don't know what this member is for

    ffhandle = ffencoder_init(&ffpar);

Any help??

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 8:17 pm
by rockcarry
Boolean wrote:I think it's good to compile the ffencoder source files to various versions.
For example, Linux, Win32(Visual C++) and Win32(MinGW32).
Like this http://libsdl.org/download-1.2.php
Yes, for someone, it's really diffcult to build ffmpeg for Win32/MSVC. You need ubuntu, mingw32-gcc, many many other related tools and environment.
So now I upload my recently ffencoder build binary for usage.

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 8:47 pm
by rockcarry
Anes wrote:Reading msdn doc i could meke it work the ffencoder.dll

The thing is that ffencoder_init() throw me and exception. I don't know if anybody apart of rockcarry uses it, but im doing the following:

Code: Select all

FFENCODER_PARAMS ffpar;
void * ffhandle;

    ffpar.filename = szMovieDir;   //this is the path to the .mp4 movie
    // video params
    ffpar.video_bitrate = 2000;
    ffpar.video_width = 256;
    ffpar.video_height = 240;
    ffpar.frame_rate = 60;
    ffpar.pixel_fmt = 32;
    ffpar.scale_flags = 0;    //i don't know what this member is for
    ffpar.start_vpts = 0;     //i don't know what this member is for
    // audio params
    ffpar.audio_bitrate = 128;
    ffpar.sample_rate = 44100;
    ffpar.channel_layout = 4;    //taken by looking in ffmpeg doc, it is "mono" i think
    ffpar.start_apts = 0;    //i don't know what this member is for
    ffpar.enable_log = 0;   //i don't know what this member is for

    ffhandle = ffencoder_init(&ffpar);

Any help??
I will explain more how to use ffencoder (also you could check test2.c of ffencode project):

1. first thing is call ffencoder_init to get a ffencoder context
you can call it like this:

Code: Select all

    void *encoder = NULL;
    encoder = ffencoder_init(NULL);
if you pass NULL to ffencoder_init function, it will using the default encoding params:

Code: Select all

    static FFENCODER_PARAMS DEF_FFENCODER_PARAMS =
    {
        "test.mp4",         // filename
        128000,             // audio_bitrate
        48000,              // sample_rate
        AV_CH_LAYOUT_STEREO,// audio stereo
        0,                  // start_apts
        512000,             // video_bitrate
        256,                // video_width
        240,                // video_height
        30,                 // frame_rate
        AV_PIX_FMT_BGRA,    // pixel_fmt
        SWS_FAST_BILINEAR,  // scale_flags
        0,                  // start_vpts
    };
if you want use your own params, you can write code like this:

Code: Select all

    FFENCODER_PARAMS params = {0};
    params.frame_rate = 60;
    nes->encoder = ffencoder_init(&params);
this means you set video frame rate to 60Hz which is for NES NTSC. The other members of params are set to 0, ffencoder_init will treat then as default values as DEF_FFENCODER_PARAMS showing above.


2. explaintion of DEF_FFENCODER_PARAMS:

Code: Select all

typedef struct
{
    // output filename
    char *filename;

    // audio params
    int audio_bitrate;   // audio encoding bitrate
    int sample_rate;     // input audio simple rate, such as 44100 or 48000
    int channel_layout;  // audio channel layout, usually we use 16bit stereo, you should use constant defined in ffmpeg header files

    int start_apts;      // start_apts & start_vpts are used to make audio & video synchronous, usually set to 0
                         // if you find that after encoding to mp4 file audio or video is running fast than each other
                         // you could try to adjust these
    // video params
    int video_bitrate;   // video encoding bitrate
    int video_width;     // width of video picture size
    int video_height;    // height of video picture size
    int frame_rate;      // frame rate of video
    int pixel_fmt;       // input pixel format, such as 16bit RGB565, 24bit RGB888, 32bit ARGB8888, please check ffmpeg header files
    int scale_flags;     // i think no need to care this
    int start_vpts;      // see above

    // for debug
    int enable_log;      // don't care this, only for debug.
} FFENCODER_PARAMS;
3. when you meet a audio want to encode, you could write code like this:

Code: Select all

    //++ ffencoder encode audio
    NES  *nes     = container_of(apu, NES, apu);
    void *data[8] = { apu->audiobuf->lpdata };
    ffencoder_audio(nes->encoder, data, apu->mixer_counter);
    //-- ffencoder encode audio
first param of ffencoder_audio is context value which returned by ffencoder_init
second param type should like void *data[8];. but only data[0] is used to store audio buffer address.
third param is the byte length of audio buffer.


4. when you meet a video want to encoder, you could write code like this:

Code: Select all

    //++ ffencoder encode video
    NES  *nes         = container_of(ppu, NES, ppu);
    void *data    [8] = { ppu->draw_buffer - 240 * ppu->draw_stride };
    int   linesize[8] = { ppu->draw_stride * 4 };
    ffencoder_video(nes->encoder, data, linesize);
    //-- ffencoder encode video
first param of ffencoder_video is context value which returned by ffencoder_init
second param type should like void *data[8];. most case only data[0] is used.
third param is the byte length of scanline stride.


5. after all things done, you could simply call:

Code: Select all

    // free ffencoder
    ffencoder_free(nes->encoder);

ffencode is now work fine in my ffnes emulator. but for your project, you need debugging.
To analyze specific issues in specific ways.

I hope these could help you.

Re: Recording and streaming emu frames

Posted: Thu Dec 25, 2014 9:05 pm
by rockcarry
Anes wrote:I know it's an off topic but i need help.

well i installed ubuntu and successfully comiled the ffencoder.dll.

I made the following to make a .lib file from the .dll:

i created a .def file with the four function names and EXPORT in the top of the file.
i ran msvc lib tool to make the .lib and it made it well.
I included the path to the .lib in msvc and put the ffencoder.lib to link to.
No luck, the compiler throw me "unresolved external symbol xxx" whree "xxx" are the functions in the .dll.
Yes, if you create a .def and only add four function names to .def, there will have some problems.
I meet the same issue when I try to create a .lib using the same method as you.
Then I use pexports tool to create a .lib from a .dll.

pexports ffencoder.dll > ffencoder.def
lib /MACHINE:X86 /DEF:ffencoder.def /OUT:ffencoder.lib

using this method, ffencoder.dll works fine in vs2005 msvc++.

I suggest you try pexports.

Re: Recording and streaming emu frames

Posted: Fri Dec 26, 2014 5:31 am
by Anes
First i had problems with the .lib file. So reading msdn i found that putting:

Code: Select all

extern "C" {
#include <ffencoder.h>
}
solved my issue of "unresolved external xxxx symbol".

Now for the implementation, when i call:

Code: Select all

    void *encoder = NULL;
    encoder = ffencoder_init(NULL);
At runtime it tells me "exception at xxxxx, cannot write to xxxx".

Any idea why it's failing?

Re: Recording and streaming emu frames

Posted: Fri Dec 26, 2014 12:08 pm
by mikejmoffitt
Anes wrote:First i had problems with the .lib file. So reading msdn i found that putting:

Code: Select all

extern "C" {
#include <ffencoder.h>
}
solved my issue of "unresolved external xxxx symbol".

Now for the implementation, when i call:

Code: Select all

    void *encoder = NULL;
    encoder = ffencoder_init(NULL);
At runtime it tells me "exception at xxxxx, cannot write to xxxx".

Any idea why it's failing?
Are you sure you are linking against it properly? Trying to execute a function that hasn't been linked will make it upset.

Re: Recording and streaming emu frames

Posted: Fri Dec 26, 2014 12:33 pm
by Anes
mikejmoffitt wrote:Are you sure you are linking against it properly? Trying to execute a function that hasn't been linked will make it upset.
i don't know. How do you link it? How would you link it?

Re: Recording and streaming emu frames

Posted: Fri Dec 26, 2014 12:44 pm
by Anes
I solved it... thanks