[Libav-user] ASS subtitle header missing while encoding
Taha Ansari
mtaha.ansari at gmail.com
Mon Dec 9 14:49:27 CET 2013
On Mon, Dec 9, 2013 at 2:55 PM, Taha Ansari <mtaha.ansari at gmail.com> wrote:
> 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...
>
Perhaps some code was missing in my original email, which I have added:
if (pCodecCtxSubtitle && pCodecCtxSubtitle->subtitle_header)
{
/* ASS code assumes this buffer is null terminated so add extra
byte. */
subtitle_st->codec->subtitle_header = (uint8_t*)
av_mallocz(pCodecCtxSubtitle->subtitle_header_size + 1);
if (!subtitle_st->codec->subtitle_header)
{
ret = AVERROR(ENOMEM);
//goto dump_format;
}
memcpy(subtitle_st->codec->subtitle_header,
pCodecCtxSubtitle->subtitle_header,
pCodecCtxSubtitle->subtitle_header_size);
subtitle_st->codec->subtitle_header_size =
pCodecCtxSubtitle->subtitle_header_size;
}
So, final code now looks like this:
#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);
if (pCodecCtxSubtitle && pCodecCtxSubtitle->subtitle_header)
{
/* ASS code assumes this buffer is null terminated so add extra
byte. */
subtitle_st->codec->subtitle_header = (uint8_t*)
av_mallocz(pCodecCtxSubtitle->subtitle_header_size + 1);
if (!subtitle_st->codec->subtitle_header)
{
ret = AVERROR(ENOMEM);
//goto dump_format;
}
memcpy(subtitle_st->codec->subtitle_header,
pCodecCtxSubtitle->subtitle_header,
pCodecCtxSubtitle->subtitle_header_size);
subtitle_st->codec->subtitle_header_size =
pCodecCtxSubtitle->subtitle_header_size;
}
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;
}
Still, based on scenario posted with 1st email, it is not working. Hope to
get some answers soon...
Thanks...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20131209/d6d96309/attachment.html>
More information about the Libav-user
mailing list