ghostscript 9.53.3 auto rotating images for some reason - java

I am using ghostsript version 9.53.3, I have an eps image. but when I try to convert it to png, it rotates it for some reason I don't understand.
here is my command which I execute in java by executing process and sending commandline args:
["C:\Program Files\gs\gs9.53.3\bin\gswin64.exe", -dNOPAUSE, -dEPSFitPage, -g88x88, -r300, -sDEVICE=png16m, -dGraphicsAlphaBits=4, -dBATCH, -sOutputFile=C:\ProgramData\InBetween\Temp\InBetweenClient\IBTemp\eps_12257004264254001602758322946eac07d9c-2366-49f1-bd2e-0181c1bef7ea.png, "D:\Trunkcheckout\IBClientServer\bin\..\Projects\myview_2356_VerpackungenPNG\Images\piktogramme/eps/2260_Erf_360.eps"]
My code:
List<String> shellCommand = new ArrayList<String>();
if (isWindowOS) {
shellCommand.add("\"" + getGSPath() + "\"");
shellCommand.add("-dNOPAUSE");
shellCommand.add("-dEPSFitPage");
width = Unit.getPixelsFromPoints(width, dpi);
height = Unit.getPixelsFromPoints(height, dpi);
shellCommand.add("-g" + width + "x" + height);
shellCommand.add("-r" + dpi);
shellCommand.add("-sDEVICE=" + device);
if (GSUtilsInterface.DEVICE_PNG.equals(device)) {
shellCommand.add("-dGraphicsAlphaBits=4");
}
shellCommand.add("-dBATCH");
shellCommand.add("-sOutputFile=" +outputFile.toString());
shellCommand.add("\"" + imagePath + "\"");
} else {
shellCommand.add("pstopdf");
shellCommand.add(imagePath);
shellCommand.add("-o");
shellCommand.add(outputFile.toString());
}
log.debug("shellCommand:" + shellCommand);
InputStream in = null;
try {
Process p;
// Process p1 = null;
log.eventLow("Executing: " + shellCommand.toString());
if (isWindowOS) {
p = new ProcessBuilder(shellCommand).start();

Try adding -dAutoRotatePages=/None

Related

file:// URI scheme in JTextPane with HTML content is not working

I'm making an image cache in the folder of my application.
I made code for downloading images and checking for their existence.
However, I cannot use them in src attributes for some reason.
I have read these two posts:
jEditorPane handling local images
Display images using JEditorPane
However, in the first question the OP said that he used another method for setting image source, that is not suitable in my case.
And the second article assumes that file:// scheme should be working out of the box without any tricks. But somehow it's not working in my case.
A tried replacing forward slashes with backslashes, replacing spaces with %20 and leaving them as they are, tried file:// and file:/// prefix - nothing is working. I can read my files using ImageIO, but JTextPane HTML renderer does not find them, so I have just error placeholders on screen.
The example of the path to an image:
file:///D:/My%20Documents/NetBeansProjects/XMessenger/cache/http%3A%2F%2Fpopov654.pp.ru%2Fcopybox%2Fphoto.jpg
Here is the code:
private int last_width = 0;
private HashMap<String, Image> imgCache = new HashMap<String, Image>();
private void createTestMessageContent(final JComponent parent) {
String html = "Some <i>text</i><br>And more,<br>And more...<br>And more...<br>And more...<br>And more...<br>And more...<br>" +
"<img src=\"http://popov654.pp.ru/copybox/photo.jpg\" width=\"390\" height=\"260\">" +
"<img src=\"http://popov654.pp.ru/copybox/DSCN2155.jpg\" width=\"390\" height=\"260\">" +
"<img src=\"http://popov654.pp.ru/copybox/DSCN2157.jpg\" width=\"390\" height=\"260\">";
html = "<div style=\"padding: 0px; font-size: 14px; font-family: Tahoma\">" + html + "</div>";
final String orig_html = html;
Matcher m = Pattern.compile("((<img src=\"[^\"]+\")( width=\"\\d+\")?( height=\"\\d+\")?([^>]*>)\\s*)+").matcher(orig_html);
while (m.find()) {
String str = m.group();
Matcher m2 = Pattern.compile("src=\"([^\"]+)\"").matcher(str);
while (m2.find()) {
File f = new File("cache");
if (!f.exists()) {
f.mkdir();
}
String src = m2.group(1);
String cached_name = src.replaceAll("/", "%2F").replaceAll(":", "%3A");
File img = new File("cache/" + cached_name);
System.err.println(img.getAbsolutePath());
if (!img.exists()) {
InputStream in = null;
BufferedInputStream b_in = null;
FileOutputStream fileOutputStream = null;
try {
in = new URL(src).openStream();
b_in = new BufferedInputStream(in);
fileOutputStream = new FileOutputStream("cache/" + cached_name);
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
//Files.copy(in, Paths.get("cache/" + cached_name), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
in.close();
b_in.close();
fileOutputStream.close();
} catch (IOException ex) {}
}
} else {
html = html.replaceFirst("src=\"" + src + "\"", "src=\"file:///" + img.getAbsolutePath().replaceAll("\\\\", "/").replaceAll(" ", "%20") + "\"");
}
}
}
final String cached_html = html;
html = html.replaceAll("(<img src=\"[^\"]+\")( width=\"\\d+\")?( height=\"\\d+\")?([^>]*>)", "$1 width=\"390\" height=\"260\" hspace=\"2\" vspace=\"8\" border=\"0\"$4");
System.out.println(html);
msgContent.setText(html);
addHyperlinkListener(msgContent);
//msgContent.setMinimumSize(new Dimension(msgContent.getWidth(), msgContent.getPreferredSize().height + 20));
//setMinimumSize(new Dimension(getWidth(), msgContent.getPreferredSize().height + 160));
setPreferredSize(new Dimension(getWidth(), msgContent.getPreferredSize().height + 148));
initImages();
updateSize();
content2.addComponentListener(new java.awt.event.ComponentListener() {
#Override
public void componentResized(ComponentEvent e) {
int new_width = ((JPanel)e.getSource()).getWidth();
if (new_width != last_width) updateImages(cached_html);
last_width = new_width;
}
#Override
public void componentMoved(ComponentEvent e) {}
#Override
public void componentShown(ComponentEvent e) {}
#Override
public void componentHidden(ComponentEvent e) {}
});
}
private void initImages() {
HTMLDocument doc = (HTMLDocument) msgContent.getStyledDocument();
Element[] imgs = getElementsByTagName(HTML.Tag.IMG, doc);
for (Element img: imgs) {
Element a = img.getParentElement();
try {
String src = (String) img.getAttributes().getAttribute(HTML.Attribute.SRC);
System.out.println("src=" + src);
System.out.println();
Image image = null;
if (!src.startsWith("http://") && !src.startsWith("https://")) {
String path = src;
if (src.startsWith("file:///")) {
path = path.substring(8).replaceAll("%20", " ");
}
image = ImageIO.read(new File(path));
} else {
image = ImageIO.read(new URL(src));
}
imgCache.put(src, image);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private void updateImages(String orig_html) {
int width = XMessengerApp.getMainWindow().getMessagePaneWidth() - 108;
double default_ratio = 16f / 9;
int img_width = (int) (width * 0.65);
int img_height = (int) ((double)img_width / default_ratio);
int margin = (int) (width * 0.005);
String html = orig_html;
Matcher m = Pattern.compile("((<img src=\"[^\"]+\")( width=\"\\d+\")?( height=\"\\d+\")?([^>]*>)\\s*)+").matcher(orig_html);
while (m.find()) {
String str = m.group();
String str_new = str;
String[] img_strs = str.split(">\\s*<");
if (img_strs.length > 1) {
System.err.println("Image series found of " + img_strs.length + " images");
}
if (img_strs.length > 1) {
img_width = (int)((width - margin * img_strs.length) / img_strs.length * 0.95);
img_height = (int)((double)img_width / default_ratio);
}
for (int i = 0; i < img_strs.length; i++) {
if (i > 0) img_strs[i] = "<" + img_strs[i];
if (i < img_strs.length-1) img_strs[i] = img_strs[i] + ">";
Matcher m2 = Pattern.compile("src=\"([^\"]+)\"").matcher(img_strs[i]);
m2.find();
String src = m2.group(1);
double ratio = default_ratio;
if (imgCache.containsKey(src)) {
Image img = imgCache.get(src);
ratio = (double) img.getWidth(null) / img.getHeight(null);
//System.out.println("Aspect ratio: " + ratio);
}
if (img_strs.length == 1) {
img_height = (int)((double)img_width / ratio);
} else {
img_width = (int)((double)img_height * ratio);
}
//System.out.println("Src: " + src);
String replace = img_strs[i].replaceAll("(<img src=\"[^\"]+\")( width=\"\\d+\")?( height=\"\\d+\")?([^>]*>)", "$1 width=\"" + img_width + "\" height=\"" + img_height + "\" hspace=\"" + margin + "\"vspace=\"8\" border=\"0\"$4");
str_new = str_new.replaceFirst(img_strs[i], replace);
}
if (img_strs.length > 1) {
str_new = "<div style=\"float: left; margin-left: -10px\">" + str_new + "</div>";
}
html = html.replaceFirst(str, str_new);
}
msgContent.setText(html);
}
private void updateSize() {
try {
Dimension d = msgContent.getPreferredSize();
Rectangle r = msgContent.modelToView(msgContent.getDocument().getLength());
d.height = r.y + r.height;
msgContent.setPreferredSize(d);
Dimension d2 = content2.getPreferredSize();
d2.height = r.y + r.height + 200;
content2.setPreferredSize(d2);
JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
topFrame.getContentPane().validate();
} catch (Exception ex) {}
}
Found the problem. It seems that I should escape % symbols in my filenames, replacing it with %25, but only if I use that path inside a URL string. When I'm using File() to work with that file it is not needed.

How to generate a PNG image from a dot file format with Graphviz

I have a java class that implements a priority queue. Then I have a class test that generates a graph like this:
digraph G {
Milan (0.0) -> Turin (1.2)
Milan (0.0) -> Montreal (7.0)
Turin (1.2) -> Paris (5.8)
Turin (1.2) -> Tokyo (2.2)
}
This graph is saved in a file called "queue".
Now I wish that this graph was displayed in a PNG image using Graphviz.
So the last call of my test files (after you have created and filled the queue with priority) is:
queue.toString("queue");
All right. The toString method is the following:
public void toString(String fileDot){
try {
FileOutputStream file = new FileOutputStream(fileDot);
PrintStream Output = new PrintStream(file);
Output.print(this.printQueue());
Output.close();
File f = new File(fileDot);
String arg1 = f.getAbsolutePath();
String arg2 = arg1 + ".png";
String[] c = {"dot", "-Tpng", arg1, "-o", arg2};
Process p = Runtime.getRuntime().exec(c);
int err = p.waitFor();
}
catch(IOException e1) {
System.out.println(e1);
}
catch(InterruptedException e2) {
System.out.println(e2);
}
}
private String printQueue() throws IOException {
String g = new String("");
char c = '"';
g = g.concat("digraph G {\n");
if(isEmpty())
g = g.concat(" " + "Empty priority queue.");
else {
for(int i = 0; i < lastIndex; i++) {
if(heap[2 * i] != null) {
g = g.concat("" + heap[i].elem + " (" + heap[i].prior + ") " + " " + " -> " + " " + "" + heap[i * 2].elem + " (" + heap[i * 2].prior + ") \n" );
if(heap[2 * i + 1] != null)
g = g.concat("" + heap[i].elem + " (" + heap[i].prior + ") " + " " + " -> " + " " + "" + heap[i * 2 + 1].elem + " (" + heap[i * 2 + 1].prior + ") \n" );
}
} //end for
} //end else
g = g.concat("}");
return g;
}
Why is not generated image .png? Where am I wrong?
Of course I installed Graphviz.
Thanks
When I ran the .dot file above through dot at the command line, I got:
$ dot -Tpng queue.dot -oqueue.png
Warning: queue.dot:2: syntax error in line 2 near '('
Thus, the parenthesised numbers in the node names are not valid in dot syntax. If you remove them, I expect the .png file would be created successfully. If you need the parenthesised numbers in your output, I suggest looking up node labels in the GraphViz documentation.
I'd also note that toString() does not seem like a particularly clear name for a function that creates a .png file so changing the name of the function might be advisable.
Try using dot's -O option instead of -o. According to dot -? here's what it does:
Automatically generate an output filename based on the input filename with a .'format' appended. (Causes all -ofile options to be ignored.)
So you could change
String[] c = {"dot", "-Tpng", arg1, "-o", arg2};
to
String[] c = {"dot", "-Tpng", arg1, "-O"};

Docx4j: PPTX got corrupted while inserting an ellipse object

i have been searching the whole day for a solution but i'm unable to find one. That's why i decided to ask a question.
My problem is that i'm inserting a ellipse object to the PPTX file. When i tries to open the presentation MS OFfice says it's corrupted and tries to repair. It ends up deleting the slide and presents the master slide.
See below my code:
the function officeXReport.getTemplatename() contains the filename of the PPTX (e.g. *Status_Report_template.pptx*)
The template pptx file contains only 1 slide.
The function officeXReport.getNewfilename() contains the new filename of the PPTX (e.g. *Status_Report_2014-03-16.pptx*)
try {
PresentationMLPackage presentationMLPackage = (PresentationMLPackage)OpcPackage.load(new java.io.File(officeXReport.getTemplatename()));
MainPresentationPart pp = presentationMLPackage.getMainPresentationPart();
boolean noLine = false;
STShapeType st = STShapeType.ELLIPSE;
int i = 1;
SlidePart slidePart = (SlidePart)presentationMLPackage.getParts().getParts().get(pp.getSlide(0).getPartName());
Shape sample = ((Shape)XmlUtils.unmarshalString(
getPresetShape(st.value(), noLine, Long.toString(1839580), Long.toString(1314971), Long.toString(184337), Long.toString(184338), "92D050"), Context.jcPML) );
slidePart.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame().add(sample);
presentationMLPackage.save(new java.io.File(officeXReport.getNewfilename()));
} catch (Exception ex) {
System.out.println("Exception thrown = " + ex.getMessage());
return null;
}
The related function getPresetShape():
private static String getPresetShape(String preset, boolean noLine, String x, String y, String cx, String cy, String colorcode) {
String txBody = "";
String ln = "";
String style = "";
if (!noLine) {
ln = "<a:ln w=\"3175\">"
+"<a:solidFill>"
+"<a:srgbClr val=\"000000\"/>"
+"</a:solidFill>"
+"</a:ln>";
style = "<p:style>\n" +
"<a:lnRef idx=\"1\">\n" +
"<a:schemeClr val=\"accent1\"/>\n" +
"</a:lnRef>\n" +
"<a:fillRef idx=\"3\">\n" +
"<a:schemeClr val=\"accent1\"/>\n" +
"</a:fillRef>\n" +
"<a:effectRef idx=\"2\">\n" +
"<a:schemeClr val=\"accent1\"/>\n" +
"</a:effectRef>\n" +
"<a:fontRef idx=\"minor\">\n" +
"<a:schemeClr val=\"lt1\"/>\n" +
"</a:fontRef>\n" +
"</p:style>";
txBody = "<p:txBody>\n" +
"<a:bodyPr rtlCol=\"false\" anchor=\"ctr\"/>\n" +
"<a:lstStyle/>\n" +
"<a:p>\n" +
"<a:pPr algn=\"ctr\"/>\n" +
"<a:endParaRPr lang=\"en-US\" sz=\"1100\" u=\"sng\" dirty=\"false\">\n" +
"<a:latin typeface=\"Futura Com Light\" panose=\"020B0402020204020303\" pitchFamily=\"34\" charset=\"0\"/>\n" +
"</a:endParaRPr>\n" +
"</a:p>\n" +
"</p:txBody>";
}
return
"<p:sp xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\">"
+ "<p:nvSpPr>"
+ "<p:cNvPr id=\"32\" name=\"Ellipse 2\" />"
+ "<p:cNvSpPr/>"
+ "<p:nvPr/>"
+ "</p:nvSpPr>"
+ "<p:spPr>"
+ "<a:xfrm>"
+ "<a:off x=\"" + x + "\" y=\"" + y + "\"/>"
+ "<a:ext cx=\"" + cx + "\" cy=\""+ cy + "\"/>"
+ "</a:xfrm>"
+ "<a:prstGeom prst=\"" + preset + "\">"
+ "<a:avLst/>"
+ "</a:prstGeom>"
+ "<a:solidFill>"
+ "<a:srgbClr val=\""+ colorcode + "\"/>"
+ "</a:solidFill>"
+ ln
+ "</p:spPr>"
+ style
+ txBody
+ "</p:sp>";
}
I have looked into the slide1.xml file which is missing the XML header compared to a correct slide1.xml file :
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
How can i get the xml header definition into the slide1.xml ?
Thanks,
Asad

CR4E Crystal Reports save modified ChartObject

I am attempting to programatically modify a chart within a Crystal Report using Java. The java then feeds the report to the viewer. Removing an item works, modifying does not.
//Experiment : Can we programatically modify a chart?
ReportDefController rdc = reportClientDocument.getReportDefController();
ReportObjectController roc = rdc.getReportObjectController();
ReportObjects ros = roc.getReportObjectsByKind(ReportObjectKind.chart);
logger.debug("There are " + ros.size() + " chart items");
IChartObject ro = null;
IChartObject ro_original = null;
ISection iSection = null;
for (int i = 0; i <ros.size(); i++){
ro = (IChartObject)ros.get(i);
ro_original = (IChartObject)ros.get(i);
String rn = ro.getName();
ChartStyle cs = (ChartStyle) ro.getChartStyle();
cs.setEnableDataAxisAutoRange(false);
cs.setEnableShowLegend(false);
cs.setEnableDepthEffect(true);
cs.setIsVertical(true);
cs.setDataAxisMinValue(-2.0);
cs.setDataAxisMaxValue(100.0);
Double minVal = (Double)cs.getDataAxisMinValue();
Double maxVal = (Double)cs.getDataAxisMaxValue();
boolean d = cs.getEnableDepthEffect();
boolean l = cs.getEnableShowLegend();
boolean a = cs.getEnableDataAxisAutoRange();
boolean v = cs.getIsVertical();
ro.setChartStyle(cs);
int sectionCode = ro.getSectionCode();
iSection = rdc.getReportDefinition().getDetailArea().getSections().getSection(0);
try
{
//roc.modify((IChartObject)ros.get(i), ro);
rdc.modifyChartObject((IChartObject)ros.get(i), ro);
reportClientDocument.refreshReportDocument();
reportClientDocument.save();
} catch (ReportSDKException e){
writer.println("Couldn't modify graph");
e.printStackTrace();
}
logger.debug("Chart named "+rn + " With Min Val " + minVal + " and Max Val " + maxVal +" with depth " + d + " and legend " + l + " autorange " + a + " Vertical " + v);
}
I've tried the modify method of ReportObjectController and the modifychartobject method of ReportDefController, and have tried refreshReportDocument and save to attempt to get something to update, but nothing's happening. Logger is showing that the values are updating as you'd expect. Any ideas?
My mistake was in not cloning the object at...
ro = (IChartObject)ros.get(i)
...so it should read...
ro = (IChartObject)ros.get(i).clone(false)
..so that..
roc.modify((IChartObject)ros.get(i), ro)
.. will now work. Hope this helps someone else having similar fun and games.

Encode video using ffmpeg from javacv on Android causes native code crash

NOTE: I have updated this since originally asking the question to reflect some of what I have learned about loading live camera images into the ffmpeg libraries.
I am using ffmpeg from javacv compiled for Android to encode/decode video for my application. (Note that originally, I was trying to use ffmpeg-java, but it has some incompatible libraries)
Original problem: The problem that I've run into is that I am currently getting each frame as a Bitmap (just a plain android.graphics.Bitmap) and I can't figure out how to stuff that into the encoder.
Solution in javacv's ffmpeg: Use avpicture_fill(), the format from Android is supposedly YUV420P, though I can't verify this until my encoder issues (below) are fixed.
avcodec.avpicture_fill((AVPicture)mFrame, picPointer, avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT)
Problem Now: The line that is supposed to actually encode the data crashes the thread. I get a big native code stack trace that I'm unable to understand. Does anybody have a suggestion?
Here is the code that I am using to instantiate all the ffmpeg libraries:
avcodec.avcodec_register_all();
avcodec.avcodec_init();
avformat.av_register_all();
mCodec = avcodec.avcodec_find_encoder(avcodec.CODEC_ID_H263);
if (mCodec == null)
{
Logging.Log("Unable to find encoder.");
return;
}
Logging.Log("Found encoder.");
mCodecCtx = avcodec.avcodec_alloc_context();
mCodecCtx.bit_rate(300000);
mCodecCtx.codec(mCodec);
mCodecCtx.width(VIDEO_WIDTH);
mCodecCtx.height(VIDEO_HEIGHT);
mCodecCtx.pix_fmt(avutil.PIX_FMT_YUV420P);
mCodecCtx.codec_id(avcodec.CODEC_ID_H263);
mCodecCtx.codec_type(avutil.AVMEDIA_TYPE_VIDEO);
AVRational ratio = new AVRational();
ratio.num(1);
ratio.den(30);
mCodecCtx.time_base(ratio);
mCodecCtx.coder_type(1);
mCodecCtx.flags(mCodecCtx.flags() | avcodec.CODEC_FLAG_LOOP_FILTER);
mCodecCtx.me_cmp(avcodec.FF_LOSS_CHROMA);
mCodecCtx.me_method(avcodec.ME_HEX);
mCodecCtx.me_subpel_quality(6);
mCodecCtx.me_range(16);
mCodecCtx.gop_size(30);
mCodecCtx.keyint_min(10);
mCodecCtx.scenechange_threshold(40);
mCodecCtx.i_quant_factor((float) 0.71);
mCodecCtx.b_frame_strategy(1);
mCodecCtx.qcompress((float) 0.6);
mCodecCtx.qmin(10);
mCodecCtx.qmax(51);
mCodecCtx.max_qdiff(4);
mCodecCtx.max_b_frames(1);
mCodecCtx.refs(2);
mCodecCtx.directpred(3);
mCodecCtx.trellis(1);
mCodecCtx.flags2(mCodecCtx.flags2() | avcodec.CODEC_FLAG2_BPYRAMID | avcodec.CODEC_FLAG2_WPRED | avcodec.CODEC_FLAG2_8X8DCT | avcodec.CODEC_FLAG2_FASTPSKIP);
if (avcodec.avcodec_open(mCodecCtx, mCodec) == 0)
{
Logging.Log("Unable to open encoder.");
return;
}
Logging.Log("Encoder opened.");
mFrameSize = avcodec.avpicture_get_size(avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT);
Logging.Log("Frame size - '" + mFrameSize + "'.");
//mPic = new AVPicture(mPicSize);
mFrame = avcodec.avcodec_alloc_frame();
if (mFrame == null)
{
Logging.Log("Unable to alloc frame.");
}
This is what I want to be able to execute next:
BytePointer picPointer = new BytePointer(data);
int bBuffSize = mFrameSize;
BytePointer bBuffer = new BytePointer(bBuffSize);
int picSize = 0;
if ((picSize = avcodec.avpicture_fill((AVPicture)mFrame, picPointer, avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT)) <= 0)
{
Logging.Log("Couldn't convert preview to AVPicture (" + picSize + ")");
return;
}
Logging.Log("Converted preview to AVPicture (" + picSize + ")");
VCAP_Package vPackage = new VCAP_Package();
if (mCodecCtx.isNull())
{
Logging.Log("Codec Context is null!");
}
//encode the image
int size = avcodec.avcodec_encode_video(mCodecCtx, bBuffer, bBuffSize, mFrame);
int totalSize = 0;
while (size >= 0)
{
totalSize += size;
Logging.Log("Encoded '" + size + "' bytes.");
//Get any delayed frames
size = avcodec.avcodec_encode_video(mCodecCtx, bBuffer, bBuffSize, null);
}
Logging.Log("Finished encoding. (" + totalSize + ")");
But, as of now, I don't know how to put the Bitmap into the right piece or if I have that setup correctly.
A few notes about the code:
- VIDEO_WIDTH = 352
- VIDEO_HEIGHT = 288
- VIDEO_FPS = 30;
After a lot of searching, I figured out that you have to load the pointers in a fairly strict and awkward manner. This is how I got everything working:
Codec setup:
avcodec.avcodec_register_all();
avcodec.avcodec_init();
avformat.av_register_all();
/* find the H263 video encoder */
mCodec = avcodec.avcodec_find_encoder(avcodec.CODEC_ID_H263);
if (mCodec == null) {
Log.d("TEST_VIDEO", "avcodec_find_encoder() run fail.");
}
mCodecCtx = avcodec.avcodec_alloc_context();
picture = avcodec.avcodec_alloc_frame();
/* put sample parameters */
mCodecCtx.bit_rate(400000);
/* resolution must be a multiple of two */
mCodecCtx.width(VIDEO_WIDTH);
mCodecCtx.height(VIDEO_HEIGHT);
/* frames per second */
AVRational avFPS = new AVRational();
avFPS.num(1);
avFPS.den(VIDEO_FPS);
mCodecCtx.time_base(avFPS);
mCodecCtx.pix_fmt(avutil.PIX_FMT_YUV420P);
mCodecCtx.codec_id(avcodec.CODEC_ID_H263);
mCodecCtx.codec_type(avutil.AVMEDIA_TYPE_VIDEO);
/* open it */
if (avcodec.avcodec_open(mCodecCtx, mCodec) < 0) {
Log.d("TEST_VIDEO", "avcodec_open() run fail.");
}
/* alloc image and output buffer */
output_buffer_size = 100000;
output_buffer = avutil.av_malloc(output_buffer_size);
size = mCodecCtx.width() * mCodecCtx.height();
picture_buffer = avutil.av_malloc((size * 3) / 2); /* size for YUV 420 */
picture.data(0, new BytePointer(picture_buffer));
picture.data(1, picture.data(0).position(size));
picture.data(2, picture.data(1).position(size / 4));
picture.linesize(0, mCodecCtx.width());
picture.linesize(1, mCodecCtx.width() / 2);
picture.linesize(2, mCodecCtx.width() / 2);
Handling the preview data:
//(1)Convert byte[] first
byte[] data420 = new byte[data.length];
convert_yuv422_to_yuv420(data, data420, VIDEO_WIDTH, VIDEO_HEIGHT);
//(2) Fill picture buffer
int data1_offset = VIDEO_HEIGHT * VIDEO_WIDTH;
int data2_offset = data1_offset * 5 / 4;
int pic_linesize_0 = picture.linesize(0);
int pic_linesize_1 = picture.linesize(1);
int pic_linesize_2 = picture.linesize(2);
//Y
for(y = 0; y < VIDEO_HEIGHT; y++)
{
for(x = 0; x < VIDEO_WIDTH; x++)
{
picture.data(0).put((y * pic_linesize_0 + x), data420[y * VIDEO_WIDTH + x]);
}
}
//Cb and Cr
for(y = 0; y < VIDEO_HEIGHT / 2; y++) {
for(x = 0; x < VIDEO_WIDTH / 2; x++) {
picture.data(1).put((y * pic_linesize_1 + x), data420[data1_offset + y * VIDEO_WIDTH / 2 + x]);
picture.data(2).put((y * pic_linesize_2 + x), data420[data2_offset + y * VIDEO_WIDTH / 2 + x]);
}
}
//(2)Encode
//Encode the image into output_buffer
out_size = avcodec.avcodec_encode_video(mCodecCtx, new BytePointer(output_buffer), output_buffer_size, picture);
Log.d("TEST_VIDEO", "Encoded '" + out_size + "' bytes");
//Delayed frames
for(; out_size > 0; i++) {
out_size = avcodec.avcodec_encode_video(mCodecCtx, new BytePointer(output_buffer), output_buffer_size, null);
Log.d("TEST_VIDEO", "Encoded '" + out_size + "' bytes");
//fwrite(output_buffer, 1, out_size, file);
}
I am still working to packetize the data, but the ongoing test project can be found here # http://code.google.com/p/test-video-encode/
Does android graphics library support the YUV format:
codecCtx.pix_fmt = AVCodecLibrary.PIX_FMT_YUV420P;
See if you can set it to ARGB or RGB32. I know the android graphics library supports this pixel format.
PS: I don't know anything about ffmpeg

Categories