[Libav-user] ASS subtitle header missing while encoding

Taha Ansari mtaha.ansari at gmail.com
Mon Dec 9 10:55:14 CET 2013


Hi all!

I am writing a small test program that will convert .SRT subtitle file to
.ASS format.

original SRT file (subtitle.srt):

1
00:00:02,000 --> 00:00:06,000
Hello

2
00:00:15,000 --> 00:00:20,000
World

3
00:01:00,000 --> 00:01:10,000
!!Again!!

Demo code:

#include "stdafx.h"

//using namespace std;

#include <iostream>
#include <fstream>

#include <string>
#include <vector>
#include <map>
//#include <DShow.h>
#include <conio.h>

#include <deque>
#include <queue>

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/dict.h"
#include "libavutil/error.h"
#include "libavutil/opt.h"
#include <libavutil/fifo.h>
#include <libavutil/imgutils.h>
#include <libavutil/samplefmt.h>
#include <libavutil/time.h>
#include <libavformat/avio.h>
#include <libavutil/avstring.h>
#include <libavutil/mathematics.h>
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/avcodec.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"

#include <libswresample/swresample.h>
}

//++decoder++//
AVFormatContext    *pFormatCtx = 0;
int                subtitleIndex = -1;
AVPacket        packet;
AVCodecContext    *pCodecCtxSubtitle = 0;
AVCodec            *pCodecSubtitle = 0;
AVSubtitle        subtitle;
//--decoder--

//++encoder++
AVFormatContext    *pOutputFormatCtx=0;
AVStream        *subtitle_st=0;
AVOutputFormat    *outputFmt=0;
AVCodec            *subtitle_codec=0;
/* Add an output stream. */
AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,
    enum AVCodecID codec_id)
{
    AVCodecContext *c;
    AVStream *st;

    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        fprintf(stderr, "Could not find encoder for '%s'\n",
            avcodec_get_name(codec_id));
        exit(1);
    }

    st = avformat_new_stream(oc, *codec);
    if (!st) {
        fprintf(stderr, "Could not allocate stream\n");
        exit(1);
    }
    st->id = oc->nb_streams-1;
    c = st->codec;

    avcodec_get_context_defaults3( c, *codec);

    switch ((*codec)->type)
    {
    case AVMEDIA_TYPE_SUBTITLE:
        break;
    default:
        break;
    }

    /* Some formats want stream headers to be separate. */
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;

    return st;
}

void open_subtitle(AVFormatContext *oc, AVCodec *codec, AVStream *st)
{
    int ret;
    AVCodecContext *c = st->codec;

    /* open the codec */
    ret = avcodec_open2(c, codec, NULL);
    if (ret < 0)
    {
        exit(1);
    }
}
//--encoder--

int main (int argc, char **argv)
{
    av_register_all();
    avcodec_register_all();
    avfilter_register_all();

    char inputFilename[90]="subtitle.srt";
    char outputFilename[90]="temp.ass";
    int rv = 0;

    // ++decoder++
    int got_subtitle = 0;
    pFormatCtx = avformat_alloc_context();

    rv = avformat_open_input(&pFormatCtx, inputFilename, NULL, NULL);

    for(int i=0; i < pFormatCtx->nb_streams; i++)
    {

if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_SUBTITLE)
        {
            subtitleIndex = i;
        }
    }
    if ( subtitleIndex >= 0 )
    {
        pCodecCtxSubtitle=pFormatCtx->streams[subtitleIndex]->codec;

        pCodecSubtitle = avcodec_find_decoder(pCodecCtxSubtitle->codec_id);
        if(pCodecSubtitle==NULL)
        {
            return -1; // Codec not found
        }
        // Open codec
        AVDictionary *codecDictOptions = NULL;
        if(avcodec_open2(pCodecCtxSubtitle, pCodecSubtitle,
&codecDictOptions) < 0 )//error
        {
        }
    }
    //--decoder--

    //++encoder++
    int ret;
    avformat_alloc_output_context2(&pOutputFormatCtx, NULL, NULL,
outputFilename);
    if (!pOutputFormatCtx)
    {
        rv = 1;
    }
    //outputFmt = pOutputFormatCtx->oformat;
    outputFmt = av_guess_format( NULL, outputFilename, NULL );
    if (outputFmt->subtitle_codec != AV_CODEC_ID_NONE)
    {
        subtitle_st = add_stream(pOutputFormatCtx, &subtitle_codec,
outputFmt->subtitle_codec);
    }

    if (subtitle_st)
        open_subtitle(pOutputFormatCtx, subtitle_codec, subtitle_st);

    av_dump_format(pOutputFormatCtx, 0, outputFilename, 1);
    /* open the output file, if needed */
    if (!(outputFmt->flags & AVFMT_NOFILE))
    {
        if (avio_open(&pOutputFormatCtx->pb, outputFilename,
AVIO_FLAG_WRITE) < 0)
        {
            rv = 1;
        }
        else
        {
            /* Write the stream header, if any. */
            if (avformat_write_header(pOutputFormatCtx, NULL) < 0)
            {
                rv = 1;
            }
        }
    }

    AVCodecContext *c = subtitle_st->codec;
    //--encoder--

    while( av_read_frame( pFormatCtx, &packet ) >= 0 )
    {
        if(packet.stream_index != subtitle_st->index)
            continue;
        int gotSubtitle = 0;
        rv = avcodec_decode_subtitle2( pCodecCtxSubtitle, &subtitle,
&gotSubtitle, &packet );
        uint64_t bufferSize = 1024 * 1024 ;
        uint8_t *buffer = new uint8_t[bufferSize];
        memset(buffer, 0, bufferSize);
        if( rv >= 0 )
        {
            rv = avcodec_encode_subtitle( subtitle_st->codec, buffer,
bufferSize, &subtitle );
            if ( rv >= 0 )
            {
                AVPacket outPacket;
                av_init_packet(&outPacket);
                outPacket.data = buffer;
                outPacket.size = strlen((const char*)buffer);
                rv = av_interleaved_write_frame(pOutputFormatCtx,
&outPacket);
                av_free_packet(&outPacket);
            }
        }
        delete [] buffer;
    }

    if ( pCodecCtxSubtitle)
    {
        avcodec_close(pCodecCtxSubtitle);
        pCodecCtxSubtitle= NULL;
    }
    if ( pCodecSubtitle )
    {
        av_free(pCodecSubtitle);
        pCodecSubtitle= NULL;
    }
    if ( pFormatCtx )
    {
        avformat_close_input(&pFormatCtx);
        avformat_free_context(pFormatCtx);
        pFormatCtx = NULL;
    }
    avcodec_close(subtitle_st->codec);
    return rv;
}

PTS values are not calculated still, it is work in progress; but the above
code gives me this output:

output temp.ass file:

Dialogue: 0,0:00:00.00,0:00:00.00,Default,Hello
Dialogue: 0,0:00:00.00,0:00:00.00,Default,World
Dialogue: 0,0:00:00.00,0:00:00.00,Default,!!Again!!

It is clearly missing all header information.

When i run ffmpeg command line to convert orignal SRT file using:

ffmpeg -i subtitle.srt temp.ass

I get:

[Script Info]
ScriptType: v4.00+

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour,
OutlineColour, BackColour, Bold, Italic, Underline, BorderStyle, Outline,
Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding
Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,1,1,0,2,10,10,10,0,0

[Events]
Format: Layer, Start, End, Style, Text
Dialogue: 0,0:00:02.00,0:00:06.00,Default,Hello
Dialogue: 0,0:00:15.00,0:00:20.00,Default,World
Dialogue: 0,0:01:00.00,0:01:10.00,Default,!!Again!!

so my question is, even though I am calling avformat_write_header()
function, why isn't this header information being written through my code?

Thanks in advance...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20131209/9ff6ae03/attachment.html>


More information about the Libav-user mailing list