Recherche avancée

Médias (1)

Mot : - Tags -/biomaping

Autres articles (55)

  • XMP PHP

    13 mai 2011, par

    Dixit Wikipedia, XMP signifie :
    Extensible Metadata Platform ou XMP est un format de métadonnées basé sur XML utilisé dans les applications PDF, de photographie et de graphisme. Il a été lancé par Adobe Systems en avril 2001 en étant intégré à la version 5.0 d’Adobe Acrobat.
    Étant basé sur XML, il gère un ensemble de tags dynamiques pour l’utilisation dans le cadre du Web sémantique.
    XMP permet d’enregistrer sous forme d’un document XML des informations relatives à un fichier : titre, auteur, historique (...)

  • Use, discuss, criticize

    13 avril 2011, par

    Talk to people directly involved in MediaSPIP’s development, or to people around you who could use MediaSPIP to share, enhance or develop their creative projects.
    The bigger the community, the more MediaSPIP’s potential will be explored and the faster the software will evolve.
    A discussion list is available for all exchanges between users.

  • Installation en mode ferme

    4 février 2011, par

    Le mode ferme permet d’héberger plusieurs sites de type MediaSPIP en n’installant qu’une seule fois son noyau fonctionnel.
    C’est la méthode que nous utilisons sur cette même plateforme.
    L’utilisation en mode ferme nécessite de connaïtre un peu le mécanisme de SPIP contrairement à la version standalone qui ne nécessite pas réellement de connaissances spécifique puisque l’espace privé habituel de SPIP n’est plus utilisé.
    Dans un premier temps, vous devez avoir installé les mêmes fichiers que l’installation (...)

Sur d’autres sites (4632)

  • ffmpeg C api cutting a video when packet dts is greater than pts

    10 mars 2017, par TastyCatFood

    Corrupted videos

    In trying to cut out a duration of one of videos using ffmpeg C api, using the code posted here : How to cut video with FFmpeg C API , ffmpeg spit out the log below :

    D/logger: Loop count:9   out: pts:0 pts_time:0 dts:2002 dts_time:0.0333667 duration:2002 duration_time:0.0333667 stream_index:1
    D/trim_video: Error muxing packet Invalid argument

    ffmpeg considercs an instruction to decompress a frame after presenting it to be a nonsense, which is well...reasonable but stringent.

    My VLC player finds the video alright and plays it of course.

    Note :

    The code immediately below is in c++ written to be compiled with g++ as I’m developing for android. For C code, scroll down further.

    My solution(g++) :

    extern "C" {
    #include "libavformat/avformat.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/timestamp.h"



    static void log_packet(
           const AVFormatContext *fmt_ctx,
           const AVPacket *pkt, const char *tag,
           long count=0)
    {

       printf("loop count %d pts:%f dts:%f duration:%f stream_index:%d\n",
              count,
              static_cast<double>(pkt->pts),
              static_cast<double>(pkt->dts),
              static_cast<double>(pkt->duration),
              pkt->stream_index);
       return;
    }

    int trimVideo(
           const char* in_filename,
           const char* out_filename,
           double cutFrom,
           double cutUpTo)
    {
       AVOutputFormat *ofmt = NULL;
       AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
       AVPacket pkt;
       int ret, i;
       //jboolean  copy = true;
       //const char *in_filename = env->GetStringUTFChars(jstring_in_filename,&amp;copy);
       //const char *out_filename = env->GetStringUTFChars(jstring_out_filename,&amp;copy);
       long loopCount = 0;

       av_register_all();

       // Cutting may change the pts and dts of the resulting video;
       // if frames in head position are removed.
       // In the case like that, src stream's copy start pts
       // need to be recorded and is used to compute the new pts value.
       // e.g.
       //    new_pts = current_pts - trim_start_position_pts;

       // nb-streams is the number of elements in AVFormatContext.streams.
       // Initial pts value must be recorded for each stream.

       //May be malloc and memset should be replaced with [].
       int64_t *dts_start_from = NULL;
       int64_t *pts_start_from = NULL;

       if ((ret = avformat_open_input(&amp;ifmt_ctx, in_filename, 0, 0)) &lt; 0) {
           printf( "Could not open input file '%s'", in_filename);
           goto end;
       }

       if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) &lt; 0) {
           printf("Failed to retrieve input stream information");
           goto end;
       }

       av_dump_format(ifmt_ctx, 0, in_filename, 0);

       avformat_alloc_output_context2(&amp;ofmt_ctx, NULL, NULL, out_filename);
       if (!ofmt_ctx) {
           printf( "Could not create output context\n");
           ret = AVERROR_UNKNOWN;
           goto end;
       }

       ofmt = ofmt_ctx->oformat;

       //preparing streams
       for (i = 0; i &lt; ifmt_ctx->nb_streams; i++) {
           AVStream *in_stream = ifmt_ctx->streams[i];
           AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
           if (!out_stream) {
               printf( "Failed allocating output stream\n");
               ret = AVERROR_UNKNOWN;
               goto end;
           }

           ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
           if (ret &lt; 0) {
               printf( "Failed to copy context from input to output stream codec context\n");
               goto end;
           }
           out_stream->codec->codec_tag = 0;
           if (ofmt_ctx->oformat->flags &amp; AVFMT_GLOBALHEADER)
               out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
       }
       av_dump_format(ofmt_ctx, 0, out_filename, 1);

       if (!(ofmt->flags &amp; AVFMT_NOFILE)) {
           ret = avio_open(&amp;ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
           if (ret &lt; 0) {
               printf( "Could not open output file '%s'", out_filename);
               goto end;
           }
       }
       //preparing the header
       ret = avformat_write_header(ofmt_ctx, NULL);
       if (ret &lt; 0) {
           printf( "Error occurred when opening output file\n");
           goto end;
       }

       // av_seek_frame translates AV_TIME_BASE into an appropriate time base.
       ret = av_seek_frame(ifmt_ctx, -1, cutFrom*AV_TIME_BASE, AVSEEK_FLAG_ANY);
       if (ret &lt; 0) {
           printf( "Error seek\n");
           goto end;
       }
       dts_start_from = static_cast(
               malloc(sizeof(int64_t) * ifmt_ctx->nb_streams));
       memset(dts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
       pts_start_from = static_cast(
               malloc(sizeof(int64_t) * ifmt_ctx->nb_streams));
       memset(pts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);

       //writing
       while (1) {
           AVStream *in_stream, *out_stream;
           //reading frame into pkt
           ret = av_read_frame(ifmt_ctx, &amp;pkt);
           if (ret &lt; 0)
               break;
           in_stream  = ifmt_ctx->streams[pkt.stream_index];
           out_stream = ofmt_ctx->streams[pkt.stream_index];

           //if end reached
           if (av_q2d(in_stream->time_base) * pkt.pts > cutUpTo) {
               av_packet_unref(&amp;pkt);
               break;
           }


           // Recording the initial pts value for each stream
           // Recording dts does not do the trick because AVPacket.dts values
           // in some video files are larger than corresponding pts values
           // and ffmpeg does not like it.
           if (dts_start_from[pkt.stream_index] == 0) {
               dts_start_from[pkt.stream_index] = pkt.pts;
               printf("dts_initial_value: %f for stream index: %d \n",
                       static_cast<double>(dts_start_from[pkt.stream_index]),
                                   pkt.stream_index

               );
           }
           if (pts_start_from[pkt.stream_index] == 0) {
               pts_start_from[pkt.stream_index] = pkt.pts;
               printf( "pts_initial_value:  %f for stream index %d\n",
                       static_cast<double>(pts_start_from[pkt.stream_index]),
                                   pkt.stream_index);
           }

           log_packet(ifmt_ctx, &amp;pkt, "in",loopCount);

           /* Computes pts etc
            *      av_rescale_q_rend etc are countering changes in time_base between
            *      out_stream and in_stream, so regardless of time_base values for
            *      in and out streams, the rate at which frames are refreshed remains
            *      the same.
            *
                   pkt.pts = pkt.pts * (in_stream->time_base/ out_stream->time_base)
                   As `time_base == 1/frame_rate`, the above is an equivalent of

                   (out_stream_frame_rate/in_stream_frame_rate)*pkt.pts where
                   frame_rate is the number of frames to be displayed per second.

                   AV_ROUND_PASS_MINMAX may set pts or dts to AV_NOPTS_VALUE
            * */


           pkt.pts =
                   av_rescale_q_rnd(
                   pkt.pts - pts_start_from[pkt.stream_index],
                   static_cast<avrational>(in_stream->time_base),
                   static_cast<avrational>(out_stream->time_base),
                   static_cast<avrounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
           pkt.dts =
                   av_rescale_q_rnd(
                   pkt.dts - dts_start_from[pkt.stream_index],
                   static_cast<avrational>(in_stream->time_base),
                   static_cast<avrational>(out_stream->time_base),
                   static_cast<avrounding>(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));

           if(pkt.dts>pkt.pts) pkt.dts = pkt.pts -1;
           if(pkt.dts &lt; 0) pkt.dts = 0;
           if(pkt.pts &lt; 0) pkt.pts = 0;

           pkt.duration = av_rescale_q(
                   pkt.duration,
                   in_stream->time_base,
                   out_stream->time_base);
           pkt.pos = -1;
           log_packet(ofmt_ctx, &amp;pkt, "out",loopCount);

           // Writes to the file after buffering packets enough to generate a frame
           // and probably sorting packets in dts order.
           ret = av_interleaved_write_frame(ofmt_ctx, &amp;pkt);
    //        ret = av_write_frame(ofmt_ctx, &amp;pkt);
           if (ret &lt; 0) {
               printf( "Error muxing packet %d \n", ret);
               //continue;
               break;
           }
           av_packet_unref(&amp;pkt);
           ++loopCount;
       }

       //Writing end code?
       av_write_trailer(ofmt_ctx);

       end:
       avformat_close_input(&amp;ifmt_ctx);

       if(dts_start_from)free(dts_start_from);
       if(pts_start_from)free(pts_start_from);

       /* close output */
       if (ofmt_ctx &amp;&amp; !(ofmt->flags &amp; AVFMT_NOFILE))
           avio_closep(&amp;ofmt_ctx->pb);
       avformat_free_context(ofmt_ctx);

       if (ret &lt; 0 &amp;&amp; ret != AVERROR_EOF) {
           //printf( "Error occurred: %s\n", av_err2str(ret));
           return 1;
       }

       return 0;
    }

    }
    </avrounding></avrational></avrational></avrounding></avrational></avrational></double></double></double></double></double>

    c compatible(Console says g++ but I’m sure this is C code)

    #include "libavformat/avformat.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/timestamp.h"



    static void log_packet(
           const AVFormatContext *fmt_ctx,
           const AVPacket *pkt, const char *tag,
           long count)
    {

       printf("loop count %d pts:%f dts:%f duration:%f stream_index:%d\n",
              count,
              (double)pkt->pts,
              (double)pkt->dts,
              (double)pkt->duration,
              pkt->stream_index);
       return;
    }

    int trimVideo(
           const char* in_filename,
           const char* out_filename,
           double cutFrom,
           double cutUpTo)
    {
       AVOutputFormat *ofmt = NULL;
       AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
       AVPacket pkt;
       int ret, i;
       //jboolean  copy = true;
       //const char *in_filename = env->GetStringUTFChars(jstring_in_filename,&amp;copy);
       //const char *out_filename = env->GetStringUTFChars(jstring_out_filename,&amp;copy);
       long loopCount = 0;

       av_register_all();

       // Cutting may change the pts and dts of the resulting video;
       // if frames in head position are removed.
       // In the case like that, src stream's copy start pts
       // need to be recorded and is used to compute the new pts value.
       // e.g.
       //    new_pts = current_pts - trim_start_position_pts;

       // nb-streams is the number of elements in AVFormatContext.streams.
       // Initial pts value must be recorded for each stream.

       //May be malloc and memset should be replaced with [].
       int64_t *dts_start_from = NULL;
       int64_t *pts_start_from = NULL;

       if ((ret = avformat_open_input(&amp;ifmt_ctx, in_filename, 0, 0)) &lt; 0) {
           printf( "Could not open input file '%s'", in_filename);
           goto end;
       }

       if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) &lt; 0) {
           printf("Failed to retrieve input stream information");
           goto end;
       }

       av_dump_format(ifmt_ctx, 0, in_filename, 0);

       avformat_alloc_output_context2(&amp;ofmt_ctx, NULL, NULL, out_filename);
       if (!ofmt_ctx) {
           printf( "Could not create output context\n");
           ret = AVERROR_UNKNOWN;
           goto end;
       }

       ofmt = ofmt_ctx->oformat;

       //preparing streams
       for (i = 0; i &lt; ifmt_ctx->nb_streams; i++) {
           AVStream *in_stream = ifmt_ctx->streams[i];
           AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
           if (!out_stream) {
               printf( "Failed allocating output stream\n");
               ret = AVERROR_UNKNOWN;
               goto end;
           }

           ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
           if (ret &lt; 0) {
               printf( "Failed to copy context from input to output stream codec context\n");
               goto end;
           }
           out_stream->codec->codec_tag = 0;
           if (ofmt_ctx->oformat->flags &amp; AVFMT_GLOBALHEADER)
               out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
       }
       av_dump_format(ofmt_ctx, 0, out_filename, 1);

       if (!(ofmt->flags &amp; AVFMT_NOFILE)) {
           ret = avio_open(&amp;ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
           if (ret &lt; 0) {
               printf( "Could not open output file '%s'", out_filename);
               goto end;
           }
       }
       //preparing the header
       ret = avformat_write_header(ofmt_ctx, NULL);
       if (ret &lt; 0) {
           printf( "Error occurred when opening output file\n");
           goto end;
       }

       // av_seek_frame translates AV_TIME_BASE into an appropriate time base.
       ret = av_seek_frame(ifmt_ctx, -1, cutFrom*AV_TIME_BASE, AVSEEK_FLAG_ANY);
       if (ret &lt; 0) {
           printf( "Error seek\n");
           goto end;
       }
       dts_start_from = (int64_t*)
               malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
       memset(dts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
       pts_start_from = (int64_t*)
               malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
       memset(pts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);

       //writing
       while (1) {
           AVStream *in_stream, *out_stream;
           //reading frame into pkt
           ret = av_read_frame(ifmt_ctx, &amp;pkt);
           if (ret &lt; 0)
               break;
           in_stream  = ifmt_ctx->streams[pkt.stream_index];
           out_stream = ofmt_ctx->streams[pkt.stream_index];

           //if end reached
           if (av_q2d(in_stream->time_base) * pkt.pts > cutUpTo) {
               av_packet_unref(&amp;pkt);
               break;
           }


           // Recording the initial pts value for each stream
           // Recording dts does not do the trick because AVPacket.dts values
           // in some video files are larger than corresponding pts values
           // and ffmpeg does not like it.
           if (dts_start_from[pkt.stream_index] == 0) {
               dts_start_from[pkt.stream_index] = pkt.pts;
               printf("dts_initial_value: %f for stream index: %d \n",
                       (double)dts_start_from[pkt.stream_index],
                                   pkt.stream_index

               );
           }
           if (pts_start_from[pkt.stream_index] == 0) {
               pts_start_from[pkt.stream_index] = pkt.pts;
               printf( "pts_initial_value:  %f for stream index %d\n",
                       (double)pts_start_from[pkt.stream_index],
                                   pkt.stream_index);
           }

           log_packet(ifmt_ctx, &amp;pkt, "in",loopCount);

           /* Computes pts etc
            *      av_rescale_q_rend etc are countering changes in time_base between
            *      out_stream and in_stream, so regardless of time_base values for
            *      in and out streams, the rate at which frames are refreshed remains
            *      the same.
            *
                   pkt.pts = pkt.pts * (in_stream->time_base/ out_stream->time_base)
                   As `time_base == 1/frame_rate`, the above is an equivalent of

                   (out_stream_frame_rate/in_stream_frame_rate)*pkt.pts where
                   frame_rate is the number of frames to be displayed per second.

                   AV_ROUND_PASS_MINMAX may set pts or dts to AV_NOPTS_VALUE
            * */


           pkt.pts =
                   av_rescale_q_rnd(
                   pkt.pts - pts_start_from[pkt.stream_index],
                   (AVRational)in_stream->time_base,
                   (AVRational)out_stream->time_base,
                   (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
           pkt.dts =
                   av_rescale_q_rnd(
                   pkt.dts - dts_start_from[pkt.stream_index],
                   (AVRational)in_stream->time_base,
                   (AVRational)out_stream->time_base,
                   AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

           if(pkt.dts>pkt.pts) pkt.dts = pkt.pts -1;
           if(pkt.dts &lt; 0) pkt.dts = 0;
           if(pkt.pts &lt; 0) pkt.pts = 0;

           pkt.duration = av_rescale_q(
                   pkt.duration,
                   in_stream->time_base,
                   out_stream->time_base);
           pkt.pos = -1;
           log_packet(ofmt_ctx, &amp;pkt, "out",loopCount);

           // Writes to the file after buffering packets enough to generate a frame
           // and probably sorting packets in dts order.
           ret = av_interleaved_write_frame(ofmt_ctx, &amp;pkt);
    //        ret = av_write_frame(ofmt_ctx, &amp;pkt);
           if (ret &lt; 0) {
               printf( "Error muxing packet %d \n", ret);
               //continue;
               break;
           }
           av_packet_unref(&amp;pkt);
           ++loopCount;
       }

       //Writing end code?
       av_write_trailer(ofmt_ctx);

       end:
       avformat_close_input(&amp;ifmt_ctx);

       if(dts_start_from)free(dts_start_from);
       if(pts_start_from)free(pts_start_from);

       /* close output */
       if (ofmt_ctx &amp;&amp; !(ofmt->flags &amp; AVFMT_NOFILE))
           avio_closep(&amp;ofmt_ctx->pb);
       avformat_free_context(ofmt_ctx);

       if (ret &lt; 0 &amp;&amp; ret != AVERROR_EOF) {
           //printf( "Error occurred: %s\n", av_err2str(ret));
           return 1;
       }

       return 0;
    }

    What is the problem

    My code does not produce the error because I’m doing new_dts = current_dts - initial_pts_for_current_stream. It works but now dts values are not properly computed.

    How to recalculate dts properly ?

    P.S

    Since Olaf seems to have a very strong opinion, posting the build console message for my main.c.
    I don’t really know C or C++ but GNU gcc seems to be calling gcc for compiling and g++ for linking.
    Well, the extension for my main is now .c and the compiler being called is gcc, so that should at least mean I have got a code written in C language...

    ------------- Build: Debug in videoTrimmer (compiler: GNU GCC Compiler)---------------

    gcc -Wall -fexceptions -std=c99 -g -I/home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include -I/usr/include -I/usr/local/include -c /home/d/CodeBlockWorkplace/videoTrimmer/main.c -o obj/Debug/main.o
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c: In function ‘log_packet’:
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:15:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
        printf("loop count %d pts:%f dts:%f duration:%f stream_index:%d\n",
               ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c: In function ‘trimVideo’:
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:79:9: warning: ‘codec’ is deprecated [-Wdeprecated-declarations]
            AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
            ^
    In file included from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:0:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:893:21: note: declared here
        AVCodecContext *codec;
                        ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:86:9: warning: ‘avcodec_copy_context’ is deprecated [-Wdeprecated-declarations]
            ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
            ^
    In file included from /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:319:0,
                    from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavcodec/avcodec.h:4286:5: note: declared here
    int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src);
        ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:86:9: warning: ‘codec’ is deprecated [-Wdeprecated-declarations]
            ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
            ^
    In file included from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:0:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:893:21: note: declared here
        AVCodecContext *codec;
                        ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:86:9: warning: ‘codec’ is deprecated [-Wdeprecated-declarations]
            ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
            ^
    In file included from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:0:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:893:21: note: declared here
        AVCodecContext *codec;
                        ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:91:9: warning: ‘codec’ is deprecated [-Wdeprecated-declarations]
            out_stream->codec->codec_tag = 0;
            ^
    In file included from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:0:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:893:21: note: declared here
        AVCodecContext *codec;
                        ^
    /home/d/CodeBlockWorkplace/videoTrimmer/main.c:93:13: warning: ‘codec’ is deprecated [-Wdeprecated-declarations]
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
                ^
    In file included from /home/d/CodeBlockWorkplace/videoTrimmer/main.c:3:0:
    /home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/include/libavformat/avformat.h:893:21: note: declared here
        AVCodecContext *codec;
                        ^
    g++ -L/home/d/Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib -L/usr/lib -L/usr/local/lib -o bin/Debug/videoTrimmer obj/Debug/main.o   ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libavformat.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libavcodec.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libavutil.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libswresample.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libswscale.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libavfilter.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libpostproc.a ../../Android/Sdk/ndk-bundle/sources/FFmpeg/local/lib/libavdevice.a -lX11 -lvdpau -lva -lva-drm -lva-x11 -ldl -lpthread -lz -llzma -lx264
    Output file is bin/Debug/videoTrimmer with size 77.24 MB
    Process terminated with status 0 (0 minute(s), 16 second(s))
    0 error(s), 8 warning(s) (0 minute(s), 16 second(s))
  • Using ffmpeg and ffserver to create a 2x1 live stream fails with unconnected output error

    31 janvier 2021, par weevilknievel

    I want to combine 2 RTSP streams (CCTV cameras) into a horizontal 2x1 strip and convert to webm for use in a HTML5 webpage.

    &#xA;&#xA;

    I am able to convert the streams into an mpeg or avi file easily, but as soon as I try to post it to ffserver ffm feed, I hit a wall.

    &#xA;&#xA;

    Here is my working ffmpeg command which writes out to a file :

    &#xA;&#xA;

    ffmpeg -rtsp_transport tcp -thread_queue_size 12 -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp" -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp" -filter_complex "[0:v][1:v] hstack=inputs=2 [v]" -map "[v]" -r 30 output.mpg&#xA;

    &#xA;&#xA;

    It seems the ffmpeg process is outputting two streams and one of them is MPEG ? In the above command I had to put a frame rate "-r 30" into the command otherwise I got an error which said that MPEG 1/2 did not support a framerate of 5/1 ??

    &#xA;&#xA;

    As soon as I try and stream to ffserver, I get an error :

    &#xA;&#xA;

    ffmpeg -rtsp_transport tcp -thread_queue_size 12 -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp" -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp" -filter_complex "[0:v][1:v] hstack=inputs=2 [v]" -map "[v]" -r 30 http://localhost:8090/feed5.ffm&#xA;

    &#xA;&#xA;

    The error I get is "Filter hstack has an unconnected output" :

    &#xA;&#xA;

    ffmpeg version N-86111-ga441aa90e8-static http://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2017 the FFmpeg developers&#xA;  built with gcc 5.4.1 (Debian 5.4.1-8) 20170304&#xA;  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-5 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libass --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg&#xA;  libavutil      55. 63.100 / 55. 63.100&#xA;  libavcodec     57. 96.101 / 57. 96.101&#xA;  libavformat    57. 72.101 / 57. 72.101&#xA;  libavdevice    57.  7.100 / 57.  7.100&#xA;  libavfilter     6. 89.101 /  6. 89.101&#xA;  libswscale      4.  7.101 /  4.  7.101&#xA;  libswresample   2.  8.100 /  2.  8.100&#xA;  libpostproc    54.  6.100 / 54.  6.100&#xA;Input #0, rtsp, from &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp&#x27;:&#xA;  Duration: N/A, start: 0.166667, bitrate: N/A&#xA;    Stream #0:0: Video: h264 (High), yuv420p(progressive), 352x288, 6 fps, 6 tbr, 90k tbn, 180k tbc&#xA;Input #1, rtsp, from &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp&#x27;:&#xA;  Duration: N/A, start: 0.166667, bitrate: N/A&#xA;    Stream #1:0: Video: h264 (High), yuv420p(progressive), 352x288, 6 fps, 6 tbr, 90k tbn, 180k tbc&#xA;Filter hstack has an unconnected output&#xA;

    &#xA;&#xA;

    My ffserver conf is very basic :

    &#xA;&#xA;

    HTTPPort 8090&#xA;HTTPBindAddress 0.0.0.0&#xA;MaxHTTPConnections 2000&#xA;MaxClients 1000&#xA;MaxBandwidth 100000&#xA;CustomLog -&#xA;&#xA;<feed>&#xA;File /mnt/ramdisk/feed5.ffm&#xA;Truncate&#xA;FileMaxSize 5M&#xA;ACL allow 127.0.0.1&#xA;</feed>&#xA;&#xA;<stream>&#xA;     Format webm&#xA;     Feed feed5.ffm&#xA;     VideoCodec libvpx&#xA;     VideoSize 640x360&#xA;     NoAudio&#xA;   AVOptionVideo quality realtime&#xA;   StartSendOnKey&#xA;   VideoBitRate 140&#xA;</stream>&#xA;&#xA;<stream>&#xA;Format status&#xA;ACL allow localhost&#xA;ACL allow 192.168.0.0 192.168.255.255&#xA;</stream>&#xA;<redirect>&#xA;URL http://www.ffmpeg.org/&#xA;</redirect>&#xA;

    &#xA;&#xA;

    Edit :

    &#xA;&#xA;

    Here is the debug output from the ffmpeg command above :

    &#xA;&#xA;

    ffmpeg -v debug -rtsp_transport tcp -thread_queue_size 12 -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp" -i "rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp" -filter_complex "[0:v][1:v] hstack=inputs=2 [v]" -map "[v]" -r 30 http://localhost:8090/feed5.ffm&#xA;ffmpeg version N-86111-ga441aa90e8-static http://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2017 the FFmpeg developers&#xA;  built with gcc 5.4.1 (Debian 5.4.1-8) 20170304&#xA;  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc-5 --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gray --enable-libass --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libzimg&#xA;  libavutil      55. 63.100 / 55. 63.100&#xA;  libavcodec     57. 96.101 / 57. 96.101&#xA;  libavformat    57. 72.101 / 57. 72.101&#xA;  libavdevice    57.  7.100 / 57.  7.100&#xA;  libavfilter     6. 89.101 /  6. 89.101&#xA;  libswscale      4.  7.101 /  4.  7.101&#xA;  libswresample   2.  8.100 /  2.  8.100&#xA;  libpostproc    54.  6.100 / 54.  6.100&#xA;Splitting the commandline.&#xA;Reading option &#x27;-v&#x27; ... matched as option &#x27;v&#x27; (set logging level) with argument &#x27;debug&#x27;.&#xA;Reading option &#x27;-rtsp_transport&#x27; ... matched as AVOption &#x27;rtsp_transport&#x27; with argument &#x27;tcp&#x27;.&#xA;Reading option &#x27;-thread_queue_size&#x27; ... matched as option &#x27;thread_queue_size&#x27; (set the maximum number of queued packets from the demuxer) with argument &#x27;12&#x27;.&#xA;Reading option &#x27;-i&#x27; ... matched as input url with argument &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp&#x27;.&#xA;Reading option &#x27;-i&#x27; ... matched as input url with argument &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp&#x27;.&#xA;Reading option &#x27;-filter_complex&#x27; ... matched as option &#x27;filter_complex&#x27; (create a complex filtergraph) with argument &#x27;[0:v][1:v] hstack=inputs=2 [v]&#x27;.&#xA;Reading option &#x27;-map&#x27; ... matched as option &#x27;map&#x27; (set input stream mapping) with argument &#x27;[v]&#x27;.&#xA;Reading option &#x27;-r&#x27; ... matched as option &#x27;r&#x27; (set frame rate (Hz value, fraction or abbreviation)) with argument &#x27;30&#x27;.&#xA;Reading option &#x27;http://localhost:8090/feed5.ffm&#x27; ... matched as output url.&#xA;Finished splitting the commandline.&#xA;Parsing a group of options: global .&#xA;Applying option v (set logging level) with argument debug.&#xA;Applying option filter_complex (create a complex filtergraph) with argument [0:v][1:v] hstack=inputs=2 [v].&#xA;Successfully parsed a group of options.&#xA;Parsing a group of options: input url rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp.&#xA;Applying option thread_queue_size (set the maximum number of queued packets from the demuxer) with argument 12.&#xA;Successfully parsed a group of options.&#xA;Opening an input file: rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp.&#xA;[tcp @ 0x58fb5e0] No default whitelist set&#xA;[rtsp @ 0x58f9700] SDP:&#xA;v=0&#xA;o=- 38990265062388 38990265062388 IN IP4 192.168.1.132&#xA;a=range:npt=0-&#xA;m=video 0 RTP/AVP 96&#xA;c=IN IP4 0.0.0.0&#xA;a=rtpmap:96 H264/90000&#xA;a=framerate:0S&#xA;a=fmtp:96 profile-level-id=640014; packetization-mode=1; sprop-parameter-sets=Z2QAFK2EAQwgCGEAQwgCGEAQwgCEK1CwSyA=,aO48sA==&#xA;a=control:trackID=3&#xA;&#xA;Failed to parse interval end specification &#x27;&#x27;&#xA;[rtsp @ 0x58f9700] video codec set to: h264&#xA;[rtsp @ 0x58f9700] RTP Profile IDC: 64 Profile IOP: 0 Level: 14&#xA;[rtsp @ 0x58f9700] RTP Packetization Mode: 1&#xA;[rtsp @ 0x58f9700] Extradata set to 0x58fb940 (size: 38)&#xA;[rtsp @ 0x58f9700] setting jitter buffer size to 0&#xA;[rtsp @ 0x58f9700] hello state=0&#xA;[h264 @ 0x58fca00] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] unknown SEI type 229&#xA;[h264 @ 0x58fca00] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] nal_unit_type: 6, nal_ref_idc: 0&#xA;[h264 @ 0x58fca00] nal_unit_type: 5, nal_ref_idc: 3&#xA;[h264 @ 0x58fca00] unknown SEI type 229&#xA;[h264 @ 0x58fca00] Reinit context to 352x288, pix_fmt: yuv420p&#xA;[h264 @ 0x58fca00] nal_unit_type: 1, nal_ref_idc: 3&#xA;    Last message repeated 5 times&#xA;[h264 @ 0x58fca00] unknown SEI type 229&#xA;    Last message repeated 1 times&#xA;[rtsp @ 0x58f9700] All info found&#xA;[rtsp @ 0x58f9700] Setting avg frame rate based on r frame rate&#xA;Input #0, rtsp, from &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=1&amp;stream=1.sdp&#x27;:&#xA;  Duration: N/A, start: 0.166667, bitrate: N/A&#xA;    Stream #0:0, 28, 1/90000: Video: h264 (High), 1 reference frame, yuv420p(progressive, left), 352x288, 0/1, 6 fps, 6 tbr, 90k tbn, 180k tbc&#xA;Successfully opened the file.&#xA;Parsing a group of options: input url rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp.&#xA;Successfully parsed a group of options.&#xA;Opening an input file: rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp.&#xA;[tcp @ 0x59f4280] No default whitelist set&#xA;[rtsp @ 0x59f7620] SDP:&#xA;v=0&#xA;o=- 38990265062388 38990265062388 IN IP4 192.168.1.132&#xA;a=range:npt=0-&#xA;m=video 0 RTP/AVP 96&#xA;c=IN IP4 0.0.0.0&#xA;a=rtpmap:96 H264/90000&#xA;a=framerate:0S&#xA;a=fmtp:96 profile-level-id=640014; packetization-mode=1; sprop-parameter-sets=Z2QAFK2EAQwgCGEAQwgCGEAQwgCEK1CwSyA=,aO48sA==&#xA;a=control:trackID=3&#xA;&#xA;Failed to parse interval end specification &#x27;&#x27;&#xA;[rtsp @ 0x59f7620] video codec set to: h264&#xA;[rtsp @ 0x59f7620] RTP Profile IDC: 64 Profile IOP: 0 Level: 14&#xA;[rtsp @ 0x59f7620] RTP Packetization Mode: 1&#xA;[rtsp @ 0x59f7620] Extradata set to 0x59f3670 (size: 38)&#xA;[rtp @ 0x59f62a0] No default whitelist set&#xA;[udp @ 0x58fb6a0] No default whitelist set&#xA;[udp @ 0x58fb6a0] end receive buffer size reported is 131072&#xA;[udp @ 0x591b940] No default whitelist set&#xA;[udp @ 0x591b940] end receive buffer size reported is 131072&#xA;[rtsp @ 0x59f7620] setting jitter buffer size to 500&#xA;[rtsp @ 0x59f7620] hello state=0&#xA;[h264 @ 0x59e4b20] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] unknown SEI type 229&#xA;[h264 @ 0x59e4b20] nal_unit_type: 7, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] nal_unit_type: 8, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] nal_unit_type: 6, nal_ref_idc: 0&#xA;[h264 @ 0x59e4b20] nal_unit_type: 5, nal_ref_idc: 3&#xA;[h264 @ 0x59e4b20] unknown SEI type 229&#xA;[h264 @ 0x59e4b20] Reinit context to 352x288, pix_fmt: yuv420p&#xA;[h264 @ 0x59e4b20] nal_unit_type: 1, nal_ref_idc: 3&#xA;    Last message repeated 5 times&#xA;[h264 @ 0x59e4b20] unknown SEI type 229&#xA;    Last message repeated 1 times&#xA;[rtsp @ 0x59f7620] All info found&#xA;[rtsp @ 0x59f7620] Setting avg frame rate based on r frame rate&#xA;Input #1, rtsp, from &#x27;rtsp://192.168.1.132:554/user=admin&amp;password=mypassword&amp;channel=2&amp;stream=1.sdp&#x27;:&#xA;  Duration: N/A, start: 0.166667, bitrate: N/A&#xA;    Stream #1:0, 28, 1/90000: Video: h264 (High), 1 reference frame, yuv420p(progressive, left), 352x288, 0/1, 6 fps, 6 tbr, 90k tbn, 180k tbc&#xA;Successfully opened the file.&#xA;detected 2 logical cores&#xA;[Parsed_hstack_0 @ 0x59f7cc0] Setting &#x27;inputs&#x27; to value &#x27;2&#x27;&#xA;Parsing a group of options: output url http://localhost:8090/feed5.ffm.&#xA;Applying option map (set input stream mapping) with argument [v].&#xA;Applying option r (set frame rate (Hz value, fraction or abbreviation)) with argument 30.&#xA;Successfully parsed a group of options.&#xA;Opening an output file: http://localhost:8090/feed5.ffm.&#xA;[http @ 0x59aa700] Setting default whitelist &#x27;http,https,tls,rtp,tcp,udp,crypto,httpproxy&#x27;&#xA;[http @ 0x59aa700] request: GET /feed5.ffm HTTP/1.1&#xA;User-Agent: Lavf/57.72.101&#xA;Accept: */*&#xA;Range: bytes=0-&#xA;Connection: close&#xA;Host: localhost:8090&#xA;Icy-MetaData: 1&#xA;&#xA;&#xA;[ffm @ 0x5917d00] Format ffm probed with size=2048 and score=101&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;video_size&#x27; to value &#x27;640x360&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;b&#x27; to value &#x27;140000&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;time_base&#x27; to value &#x27;1/5&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;bt&#x27; to value &#x27;35000&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;rc_eq&#x27; to value &#x27;tex^qComp&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;maxrate&#x27; to value &#x27;280000&#x27;&#xA;[NULL @ 0x5bce3e0] Setting entry with key &#x27;bufsize&#x27; to value &#x27;280000&#x27;&#xA;[AVIOContext @ 0x5915b80] Statistics: 4096 bytes read, 0 seeks&#xA;[http @ 0x5915f00] Setting default whitelist &#x27;http,https,tls,rtp,tcp,udp,crypto,httpproxy&#x27;&#xA;[http @ 0x5915f00] request: POST /feed5.ffm HTTP/1.1&#xA;Transfer-Encoding: chunked&#xA;User-Agent: Lavf/57.72.101&#xA;Accept: */*&#xA;Connection: close&#xA;Host: localhost:8090&#xA;Icy-MetaData: 1&#xA;&#xA;&#xA;Successfully opened the file.&#xA;Filter hstack has an unconnected output&#xA;[AVIOContext @ 0x59ab080] Statistics: 0 seeks, 0 writeouts&#xA;

    &#xA;&#xA;

    I am stumped - any clues ?

    &#xA;&#xA;

    Thanks in advance.

    &#xA;

  • CD-R Read Speed Experiments

    21 mai 2011, par Multimedia Mike — Science Projects, Sega Dreamcast

    I want to know how fast I can really read data from a CD-R. Pursuant to my previous musings on this subject, I was informed that it is inadequate to profile reading just any file from a CD-R since data might be read faster or slower depending on whether the data is closer to the inside or the outside of the disc.

    Conclusion / Executive Summary
    It is 100% true that reading data from the outside of a CD-R is faster than reading data from the inside. Read on if you care to know the details of how I arrived at this conclusion, and to find out just how much speed advantage there is to reading from the outside rather than the inside.

    Science Project Outline

    • Create some sample CD-Rs with various properties
    • Get a variety of optical drives
    • Write a custom program that profiles the read speed

    Creating The Test Media
    It’s my understanding that not all CD-Rs are created equal. Fortunately, I have 3 spindles of media handy : Some plain-looking Memorex discs, some rather flamboyant Maxell discs, and those 80mm TDK discs :



    My approach for burning is to create a single file to be burned into a standard ISO-9660 filesystem. The size of the file will be the advertised length of the CD-R minus 1 megabyte for overhead— so, 699 MB for the 120mm discs, 209 MB for the 80mm disc. The file will contain a repeating sequence of 0..0xFF bytes.

    Profiling
    I don’t want to leave this to the vagaries of any filesystem handling layer so I will conduct this experiment at the sector level. Profiling program outline :

    • Read the CD-ROM TOC and get the number of sectors that comprise the data track
    • Profile reading the first 20 MB of sectors
    • Profile reading 20 MB of sectors in the middle of the track
    • Profile reading the last 20 MB of sectors

    Unfortunately, I couldn’t figure out the raw sector reading on modern Linux incarnations (which is annoying since I remember it being pretty straightforward years ago). So I left it to the filesystem after all. New algorithm :

    • Open the single, large file on the CD-R and query the file length
    • Profile reading the first 20 MB of data, 512 kbytes at a time
    • Profile reading 20 MB of sectors in the middle of the track (starting from filesize / 2 - 10 MB), 512 kbytes at a time
    • Profile reading the last 20 MB of sectors (starting from filesize - 20MB), 512 kbytes at a time

    Empirical Data
    I tested the program in Linux using an LG Slim external multi-drive (seen at the top of the pile in this post) and one of my Sega Dreamcast units. I gathered the median value of 3 runs for each area (inner, middle, and outer). I also conducted a buffer flush in between Linux runs (as root : 'sync; echo 3 > /proc/sys/vm/drop_caches').

    LG Slim external multi-drive (reading from inner, middle, and outer areas in kbytes/sec) :

    • TDK-80mm : 721, 897, 1048
    • Memorex-120mm : 1601, 2805, 3623
    • Maxell-120mm : 1660, 2806, 3624

    So the 120mm discs can range from about 10.5X all the way up to a full 24X on this drive. For whatever reason, the 80mm disc fares a bit worse — even at the inner track — with a range of 4.8X - 7X.

    Sega Dreamcast (reading from inner, middle, and outer areas in kbytes/sec) :

    • TDK-80mm : 502, 632, 749
    • Memorex-120mm : 499, 889, 1143
    • Maxell-120mm : 500, 890, 1156

    It’s interesting that the 80mm disc performed comparably to the 120mm discs in the Dreamcast, in contrast to the LG Slim drive. Also, the results are consistent with my previous profiling experiments, which largely only touched the inner area. The read speeds range from 3.3X - 7.7X. The middle of a 120mm disc reads at about 6X.

    Implications
    A few thoughts regarding these results :

    • Since the very definition of 1X is the minimum speed necessary to stream data from an audio CD, then presumably, original 1X CD-ROM drives would have needed to be capable of reading 1X from the inner area. I wonder what the max read speed at the outer edges was ? It’s unlikely I would be able to get a 1X drive working easily in this day and age since the earliest CD-ROM drives required custom controllers.
    • I think 24X is the max rated read speed for CD-Rs, at least for this drive. This implies that the marketing literature only cites the best possible numbers. I guess this is no surprise, similar to how monitors and TVs have always been measured by their diagonal dimension.
    • Given this data, how do you engineer an ISO-9660 filesystem image so that the timing-sensitive multimedia files live on the outermost track ? In the Dreamcast case, if you can guarantee your FMV files will live somewhere between the middle and the end of the disc, you should be able to count on a bitrate of at least 900 kbytes/sec.

    Source Code
    Here is the program I wrote for profiling. Note that the filename is hardcoded (#define FILENAME). Compiling for Linux is a simple 'gcc -Wall profile-cdr.c -o profile-cdr'. Compiling for Dreamcast is performed in the standard KallistiOS manner (people skilled in the art already know what they need to know) ; the only variation is to compile with the '-D_arch_dreamcast' flag, which the default KOS environment adds anyway.

    C :
    1. #ifdef _arch_dreamcast
    2.   #include <kos .h>
    3.  
    4.   /* map I/O functions to their KOS equivalents */
    5.   #define open fs_open
    6.   #define lseek fs_seek
    7.   #define read fs_read
    8.   #define close fs_close
    9.  
    10.   #define FILENAME "/cd/bigfile"
    11. #else
    12.   #include <stdio .h>
    13.   #include <sys /types.h>
    14.   #include </sys><sys /stat.h>
    15.   #include </sys><sys /time.h>
    16.   #include <fcntl .h>
    17.   #include <unistd .h>
    18.  
    19.   #define FILENAME "/media/Full disc/bigfile"
    20. #endif
    21.  
    22. /* Get a current absolute millisecond count ; it doesn’t have to be in
    23. * reference to anything special. */
    24. unsigned int get_current_milliseconds()
    25. {
    26. #ifdef _arch_dreamcast
    27.   return timer_ms_gettime64() ;
    28. #else
    29.   struct timeval tv ;
    30.   gettimeofday(&tv, NULL) ;
    31.   return tv.tv_sec * 1000 + tv.tv_usec / 1000 ;
    32. #endif
    33. }
    34.  
    35. #define READ_SIZE (20 * 1024 * 1024)
    36. #define READ_BUFFER_SIZE (512 * 1024)
    37.  
    38. int main()
    39. {
    40.   int i, j ;
    41.   int fd ;
    42.   char read_buffer[READ_BUFFER_SIZE] ;
    43.   off_t filesize ;
    44.   unsigned int start_time, end_time ;
    45.  
    46.   fd = open(FILENAME, O_RDONLY) ;
    47.   if (fd == -1)
    48.   {
    49.     printf("could not open %s\n", FILENAME) ;
    50.     return 1 ;
    51.   }
    52.   filesize = lseek(fd, 0, SEEK_END) ;
    53.  
    54.   for (i = 0 ; i <3 ; i++)
    55.   {
    56.     if (i == 0)
    57.     {
    58.       printf("reading inner 20 MB...\n") ;
    59.       lseek(fd, 0, SEEK_SET) ;
    60.     }
    61.     else if (i == 1)
    62.     {
    63.       printf("reading middle 20 MB...\n") ;
    64.       lseek(fd, (filesize / 2) - (READ_SIZE / 2), SEEK_SET) ;
    65.     }
    66.     else
    67.     {
    68.       printf("reading outer 20 MB...\n") ;
    69.       lseek(fd, filesize - READ_SIZE, SEEK_SET) ;
    70.     }
    71.     /* read 20 MB ; 40 chunks of 1/2 MB */
    72.     start_time = get_current_milliseconds() ;
    73.     for (j = 0 ; j <(READ_SIZE / READ_BUFFER_SIZE) ; j++)
    74.       if (read(fd, read_buffer, READ_BUFFER_SIZE) != READ_BUFFER_SIZE)
    75.       {
    76.         printf("read error\n") ;
    77.         break ;
    78.       }
    79.     end_time = get_current_milliseconds() ;
    80.     printf("%d - %d = %d ms => %d kbytes/sec\n",
    81.       end_time, start_time, end_time - start_time,
    82.       READ_SIZE / (end_time - start_time)) ;
    83.   }
    84.  
    85.   close(fd) ;
    86.  
    87.   return 0 ;
    88. }